所以,我正在尝试构建一个SNMP轮询服务,以便从我的网络设备中获取一些库存数据。我可以使用netsnmp或easysnmp模块连接到设备。
当我尝试更改哪些MIB用于查询某些更具企业特性的内容(例如Force10网络设备的“chStackUnitTable”)时,问题就出现了。
由于我无法在查询设备的sysObjectId.0之前说明要加载哪个mib,我必须首先查询设备,然后告诉net-snmp绑定(netsnmp和easysnmp都依赖它)查看通过设置os.environ['MIBDIRS']
变量来确定特定目录。
问题似乎是在使用这些绑定的第一个方法调用之后,net-snmp绑定忽略了对MIBDIRS环境变量的更改。
使用Force10 S3048-ON开关的示例:
import os
import netsnmp
mib_dir_root = "/opt/project/var/lib/snmp/mibs"
session_options = {'DestHost': "10.0.0.254", 'Version': 2, 'Community': "public"}
s = netsnmp.Session(**session_options)
vl = netsnmp.VarList(netsnmp.Varbind('sysObjectID', 0))
_r = s.get(vl)
obj_id = vl[0].val
print('{:s}.{:s}: {:s}'.format(vl.tag, vl.iid, vl.val))
# output: "sysObjectID.0: .1.3.6.1.4.1.6027.1.3.23"
# We can now determine which MIB to use to get the interesting stuff (serial number,
# service tag, etc) by inspecting the obj_id. In this case we know we want to query
# the chStackUnitTable of the F10-S-SERIES-CHASSIS-MIB mib.
# Let's add the MIB directory to our MIBDIRS environment variable
mib_dir = os.path.join(mib_dir_root, 'Force10')
os.environ['MIBDIRS'] = "+{:s}".format(mib_dir))
# We also have the annoyance here of having another mib (F10-M-SERIES-CHASSIS-MIB)
# that has the same OID name of 'chStackUnitTable' at a different numeric OID. So we
# need to specify the MIB explicitly
mib = 'F10-S-SERIES-CHASSIS-MIB'
oid = 'chStackUnitTable'
vl = netsnmp.VarList(netsnmp.Varbind('{:s}:{:s}'.format(mib, oid)))
s.walk(vl)
# output:
# MIB search path: /home/username/.snmp/mibs;/usr/share/snmp/mibs
# Cannot find module (F10-S-SERIES-CHASSIS-MIB): At line 1 in (none)
# snmp_build: unknown failure
但是,如果我在调用netsnmp绑定之前添加MIBDIRS环境变量,它可以工作:
import os
import netsnmp
mib_dir_root = "/opt/project/var/lib/snmp/mibs"
mib_dirs = ['Force10', 'Cisco', 'Dell']
mib_dirs = [os.path.join(mib_dir_root, d) for d in mib_dirs if os.path.isdir(os.path.join(mib_dir_root, d))]
os.environ['MIBDIRS'] = "+{:s}".format(";".join(mib_dirs))
print(os.environ['MIBDIRS'])
# output:
# +/opt/project/var/lib/snmp/mibs/Force10;/opt/project/var/lib/snmp/mibs/Cisco;/opt/project/var/lib/snmp/mibs/Dell;
session_options = {'DestHost': "10.0.0.254", 'Version': 2, 'Community': "public"}
s = netsnmp.Session(**session_options)
vl = netsnmp.VarList(netsnmp.Varbind('sysObjectID', 0))
_r = s.get(vl)
obj_id = vl[0].val
print('{:s}.{:s}: {:s}'.format(vl.tag, vl.iid, vl.val))
# output: "sysObjectID.0: .1.3.6.1.4.1.6027.1.3.23"
mib = 'F10-S-SERIES-CHASSIS-MIB'
oid = 'chStackUnitTable'
vl = netsnmp.VarList(netsnmp.Varbind('{:s}:{:s}'.format(mib, oid)))
_r = s.walk(vl)
cols = ['chStackUnitSerialNumber', 'chStackUnitModelID', 'chStackUnitCodeVersion', 'chStackUnitServiceTag']
for v in vl:
if v.tag in cols:
print('{:s}.{:s}: {:s}'.format(v.tag, v.iid, v.val))
# output:
# chStackUnitModelID.1: S3048-ON-01-FE-52T
# chStackUnitCodeVersion.1: 9.8(0.0P2)
# chStackUnitSerialNumber.1: NA
# chStackUnitServiceTag.1: <REDACTED>
我对此解决方案的问题是可扩展性。我计划支持许多不同的设备,并且每个制造商都需要一个MIB目录。这意味着MIBDIRS和MIB搜索路径将变得非常糟糕。更不用说net-snmp绑定可能会在某个阶段剥落,因为它必须搜索可能数千个MIB文件。
有没有办法在第一次snmp查询完成后清除绑定,设置MIBDIRS变量,然后重新导入netsnmp模块?我尝试使用reload(netsnmp)
,但这似乎不起作用。
理想情况下,这样的事情:
...
sess.get(object_id)
# determine which mib dir to point to
os.environ['MIBDIRS'] = "+" + "path_to_mib_dir"
# magic reloading of netsnmp
sess = netsnmp.Session(**session_options)
varlist = netsnmp.VarList(netsnmp.Varbind(mib + ":" + table_oid))
sess.walk(varlist)
...
# Profit!!!