如何从 pysnmp 中的陷阱变量绑定中正确获取 table 行索引和命名值

How to properly get table-row indexes and named values from trapped var-binds in pysnmp

我正在努力使我的代码尽可能干净,但我对目前所取得的成就并不完全满意。

我构建了一个 SNMP 管理器,它使用自定义 MIB 从另一台设备接收陷阱,我将其称为 MY-MIB。

我不确定这是最干净的方法,但基本上我有:

from pysnmp.entity import engine, config
from pysnmp.carrier.asynsock.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv, context
from pysnmp.smi import builder, rfc1902
from pysnmp.smi.view import MibViewController
from pysnmp.entity.rfc3413 import mibvar

_snmp_engine = engine.SnmpEngine()
_snmpContext = context.SnmpContext(_snmpEngine)
_mibBuilder = _snmpContext.getMibInstrum().getMibBuilder()
#Add local path where MY-MIB is located
_mibSources = _mibBuilder.getMibSources() + (builder.DirMibSource('.'),)
_mibBuilder.setMibSources(*mibSources)
_mibBuilder.loadModules('MY-MIB')
_view_controller = MibViewController(_mibBuilder)    


def my_callback_trap_processor(snmp_engine, state_reference,
                                   context_id, context_name, var_binds, ctx):

    #...CALLBACK CODE...


config.addV1System(snmp_engine, 'my-area', 'MYCOMMUNITY')
config.addTargetParams(snmp_engine, 'my-creds', 'my-area',
                       'noAuthNoPriv', 1)

config.addSocketTransport(snmp_engine,
                          udp.domainName + (1,),
                          udp.UdpTransport().openServerMode((IP_ADDRESS,
                                                             PORT)))

ntfrcv.NotificationReceiver(snmp_engine, my_callback_trap_processor)

snmp_engine.transportDispatcher.jobStarted(1)

try:
    snmp_engine.transportDispatcher.runDispatcher()
except:
    snmp_engine.transportDispatcher.closeDispatcher()
    raise

在上面的回调函数中,我可以通过使用以下代码得到一个非常清晰的打印:

    varBinds = [rfc1902.ObjectType(rfc1902.ObjectIdentity(x[0]), x[1]).resolveWithMib(_view_controller) for x in var_binds]
    for varBind in varBinds:
        print(varBind.prettyPrint())

从我收到的给定陷阱中,它给了我:

SNMPv2-MIB::sysUpTime.0 = 0
SNMPv2-MIB::snmpTrapOID.0 = MY-MIB::myNotificationType
MY-MIB::myReplyKey.47746."ABC" = 0x00000000000000000000000000000000000
MY-MIB::myTime.0 = 20171115131544Z
MY-MIB::myOperationMode.0 = 'standalone'

不错。但我想 manipulate/dissect 来自给定 var-binds 的每一位信息,尤其是以更高级别的方式。

查看库的内部结构,我能够收集到这段代码:

for varBind in var_binds:   
    objct = rfc1902.ObjectIdentity(varBind[0]).resolveWithMib(self._view_controller)
    (symName, modName), indices = mibvar.oidToMibName(
                self._view_controller, objct.getOid()
                )
    print(symName, modName, indices, varBind[1])

这给了我:

sysUpTime SNMPv2-MIB (Integer(0),) 0
snmpTrapOID SNMPv2-MIB (Integer(0),) 1.3.6.1.X.Y.Z.A.B.C.D
myReplyKey MY-MIB (myTimeStamp(47746), myName(b'X00080')) 0x00000000000000000000000000000000000
myTime MY-MIB (Integer(0),) 20171115131544Z
myOperationMode MY-MIB (Integer(0),) 1

对于 myReplyKey 索引,我可以做一个:

    for idx in indices:
        try:
            print(idx.getValue())
        except AttributeError:
            print(int(idx))

但是在 myOperationMode var-bind 的情况下,我如何获得命名值 'standalone' 而不是 1?以及如何获取索引的名称(myTimeStampmyName)?

更新:

根据 Ilya 的建议,我对库进行了更多研究以获取 namedValues,而且,我使用了一些 Python hacking 来获取我在索引中寻找的内容。

varBinds = [rfc1902.ObjectType(rfc1902.ObjectIdentity(x[0]), x[1]).resolveWithMib(_view_controller) for x in var_binds]
processed_var_binds = []
for var_bind in resolved_var_binds:   

    object_identity, object_value = var_bind
    mod_name, var_name, indices = object_identity.getMibSymbol()

    var_bind_dict = {'mib': mod_name, 'name': var_name, 'indices': {}}

    for idx in indices:
        try:
            value = idx.getValue()
        except AttributeError:
            var_bind_dict['indices'] = int(idx.prettyPrint())
        else:
            var_bind_dict['indices'][type(value).__name__] = str(value)

    try:
        var_bind_dict['value'] = object_value.namedValues[object_value]
    except (AttributeError, KeyError):
        try:
            var_bind_dict['value'] = int(object_value.prettyPrint())
        except ValueError:
            var_bind_dict['value'] = object_value.prettyPrint()

    processed_var_binds.append(var_bind_dict)

要解决针对 MIB 的 SNMP PDU var 绑定,您可以使用 this snippet 我认为您已经完成的操作:

from pysnmp.smi.rfc1902 import *

var_binds = [ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController)
            for x in var_binds]

至此,您已经有了 rfc1902.ObjectType objects. The ObjectType instance mimics a two-element tuple: ObjectIdentity and SNMP value object.

的列表
var_bind = var_binds[0]
object_identity, object_value = var_bind

现在,getMibSymbol() will give you MIB name, MIB object name and the tuple of indices made up from the trailing part of the OID. Index elements are SNMP value objects 就像 object_value:

>>> object_identity.getMibSymbol()
('SNMPv2-MIB', 'sysDescr', (0,))

枚举(如果存在)由 .prettyPrint() 报告:

>>> from pysnmp.proto.rfc1902 import *
>>> Error = Integer.withNamedValues(**{'disk-full': 1, 'no-disk': -1})
>>> error = Error(1)
>>> error.prettyPrint()
'disk-full'
>>> int(error)
1