Python - динамические MIB с помощью netsnmp / easysnmp
Итак, я пытаюсь создать службу опроса SNMP, чтобы получить данные инвентаризации от моих сетевых устройств. Я могу подключиться к устройствам с помощью модулей netsnmp или easysnmp.
Проблема возникает, когда я пытаюсь изменить MIB, которые нужно использовать для запроса некоторых более специфичных для предприятия вещей, таких как chStackUnitTable сетевого устройства Force10.
Поскольку я не могу сказать, какой mib загружать до запроса oid устройства sysObjectId.0, я сначала должен запросить устройство, а затем указать привязкам 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
Работает но плохо
Однако, если я добавлю переменную среды MIBDIRS до вызова привязок netsnmp, это сработает:
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!!!