带异步的 PySNMP 仪器控制器
PySNMP Instrumentation Controller with asyncio
我需要编写简单的 SNMP 响应程序,其中部分工作是通过 asyncio.subprocess
模块调用一些外部脚本。现在我正在试验 pysnmp
,但是从示例中稍微修改后的代码不起作用:
import asyncio
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.carrier.asyncio.dgram import udp
from pysnmp.smi import instrum
from pysnmp.proto.api import v2c
snmpEngine = engine.SnmpEngine()
config.addTransport(
snmpEngine,
udp.domainName,
udp.UdpTransport().openServerMode(('0.0.0.0', 161))
)
# config.addV1System(snmpEngine, 'my-area', 'public')
config.addV1System(snmpEngine, 'public', 'public', contextName='my-context')
config.addV1System(snmpEngine, 'private', 'private', contextName='my-context')
# Allow full MIB access for each user at VACM
config.addVacmUser(snmpEngine, 2, "public", 'noAuthNoPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1))
config.addVacmUser(snmpEngine, 2, "private", 'noAuthNoPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1))
# Create an SNMP context
snmpContext = context.SnmpContext(snmpEngine)
# Very basic Management Instrumentation Controller without
# any Managed Objects attached. It supports only GET's and
# always echos request var-binds in response.
class EchoMibInstrumController(instrum.AbstractMibInstrumController):
@asyncio.coroutine
def readVars(self, varBinds, acInfo=(None, None)):
yield from asyncio.sleep(1)
return [(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds]
# Create a custom Management Instrumentation Controller and register at
# SNMP Context under ContextName 'my-context'
snmpContext.registerContextName(
v2c.OctetString('my-context'), # Context Name
EchoMibInstrumController() # Management Instrumentation
)
# Register GET&SET Applications at the SNMP engine for a custom SNMP context
cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
cmdrsp.SetCommandResponder(snmpEngine, snmpContext)
loop = asyncio.get_event_loop()
loop.run_forever()
当尝试使用以下命令进行查询时 snmpget -v 2c -c public 127.0.0.1 .1.3.6.1.2.1.1.1.0
脚本失败并出现以下回溯。
Exception in callback AbstractTransportDispatcher._cbFun(<pysnmp.carri...x7f4c7540d518>, ('127.0.0.1', 44209), b'0)\x02\x01\...1\x00\x05\x00')
handle: <Handle AbstractTransportDispatcher._cbFun(<pysnmp.carri...x7f4c7540d518>, ('127.0.0.1', 44209), b'0)\x02\x01\...1\x00\x05\x00')>
Traceback (most recent call last):
File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
self._callback(*self._args)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/carrier/base.py", line 70, in _cbFun
self, transportDomain, transportAddress, incomingMessage
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/engine.py", line 154, in __receiveMessageCbFun
self, transportDomain, transportAddress, wholeMsg
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/rfc3412.py", line 421, in receiveMessage
PDU, maxSizeResponseScopedPDU, stateReference)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 140, in processPdu
(self.__verifyAccess, snmpEngine))
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 247, in handleMgmtOperation
mgmtFun(v2c.apiPDU.getVarBinds(PDU), (acFun, acCtx)))
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 46, in sendVarBinds
v2c.apiPDU.setVarBinds(PDU, varBinds)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/api/v1.py", line 135, in setVarBinds
varBindList.getComponentByPosition(idx), varBind
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/api/v1.py", line 38, in setOIDVal
oid, val = oidVal[0], oidVal[1]
TypeError: 'Future' object does not support indexing
可能是我在做一些愚蠢的事情,我承认我对 SNMP 了解不多,那么请指点我正确的方向。
发生这种情况是因为 CommandResponder <-> MIB 控制器交互是 currently synchronous。换句话说,你不能 yield from
MIB 控制器,你只能 return
来自它。它不能是 coroutine
。删除这两件事后,您的代码可能会正常工作。
以 mgmtFun
(在我上面链接的代码中)可以 return Future
触发其余代码的方式重构 pysnmp 代码绝对是可行的(例如sendVarBinds
) 一旦 Future
完成。这将使您的 MIB 控制器异步。
这就是你需要的?然后考虑针对 pysnmp 的 PR 或 FR。
我需要编写简单的 SNMP 响应程序,其中部分工作是通过 asyncio.subprocess
模块调用一些外部脚本。现在我正在试验 pysnmp
,但是从示例中稍微修改后的代码不起作用:
import asyncio
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.carrier.asyncio.dgram import udp
from pysnmp.smi import instrum
from pysnmp.proto.api import v2c
snmpEngine = engine.SnmpEngine()
config.addTransport(
snmpEngine,
udp.domainName,
udp.UdpTransport().openServerMode(('0.0.0.0', 161))
)
# config.addV1System(snmpEngine, 'my-area', 'public')
config.addV1System(snmpEngine, 'public', 'public', contextName='my-context')
config.addV1System(snmpEngine, 'private', 'private', contextName='my-context')
# Allow full MIB access for each user at VACM
config.addVacmUser(snmpEngine, 2, "public", 'noAuthNoPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1))
config.addVacmUser(snmpEngine, 2, "private", 'noAuthNoPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1))
# Create an SNMP context
snmpContext = context.SnmpContext(snmpEngine)
# Very basic Management Instrumentation Controller without
# any Managed Objects attached. It supports only GET's and
# always echos request var-binds in response.
class EchoMibInstrumController(instrum.AbstractMibInstrumController):
@asyncio.coroutine
def readVars(self, varBinds, acInfo=(None, None)):
yield from asyncio.sleep(1)
return [(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds]
# Create a custom Management Instrumentation Controller and register at
# SNMP Context under ContextName 'my-context'
snmpContext.registerContextName(
v2c.OctetString('my-context'), # Context Name
EchoMibInstrumController() # Management Instrumentation
)
# Register GET&SET Applications at the SNMP engine for a custom SNMP context
cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
cmdrsp.SetCommandResponder(snmpEngine, snmpContext)
loop = asyncio.get_event_loop()
loop.run_forever()
当尝试使用以下命令进行查询时 snmpget -v 2c -c public 127.0.0.1 .1.3.6.1.2.1.1.1.0
脚本失败并出现以下回溯。
Exception in callback AbstractTransportDispatcher._cbFun(<pysnmp.carri...x7f4c7540d518>, ('127.0.0.1', 44209), b'0)\x02\x01\...1\x00\x05\x00')
handle: <Handle AbstractTransportDispatcher._cbFun(<pysnmp.carri...x7f4c7540d518>, ('127.0.0.1', 44209), b'0)\x02\x01\...1\x00\x05\x00')>
Traceback (most recent call last):
File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
self._callback(*self._args)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/carrier/base.py", line 70, in _cbFun
self, transportDomain, transportAddress, incomingMessage
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/engine.py", line 154, in __receiveMessageCbFun
self, transportDomain, transportAddress, wholeMsg
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/rfc3412.py", line 421, in receiveMessage
PDU, maxSizeResponseScopedPDU, stateReference)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 140, in processPdu
(self.__verifyAccess, snmpEngine))
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 247, in handleMgmtOperation
mgmtFun(v2c.apiPDU.getVarBinds(PDU), (acFun, acCtx)))
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/entity/rfc3413/cmdrsp.py", line 46, in sendVarBinds
v2c.apiPDU.setVarBinds(PDU, varBinds)
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/api/v1.py", line 135, in setVarBinds
varBindList.getComponentByPosition(idx), varBind
File "/opt/profiset2/lib/python3.4/site-packages/pysnmp/proto/api/v1.py", line 38, in setOIDVal
oid, val = oidVal[0], oidVal[1]
TypeError: 'Future' object does not support indexing
可能是我在做一些愚蠢的事情,我承认我对 SNMP 了解不多,那么请指点我正确的方向。
发生这种情况是因为 CommandResponder <-> MIB 控制器交互是 currently synchronous。换句话说,你不能 yield from
MIB 控制器,你只能 return
来自它。它不能是 coroutine
。删除这两件事后,您的代码可能会正常工作。
以 mgmtFun
(在我上面链接的代码中)可以 return Future
触发其余代码的方式重构 pysnmp 代码绝对是可行的(例如sendVarBinds
) 一旦 Future
完成。这将使您的 MIB 控制器异步。
这就是你需要的?然后考虑针对 pysnmp 的 PR 或 FR。