diff options
author | elie <elie> | 2015-09-27 10:26:25 +0000 |
---|---|---|
committer | elie <elie> | 2015-09-27 10:26:25 +0000 |
commit | 627d9ff4a3715477e56fe397f099ad0db0d5c1b9 (patch) | |
tree | 60cdd6f446e892194122abad0dfa4c6413eb4374 /pysnmp | |
parent | bdfbce73382678e0288d8bc8d3093c827b05e1d1 (diff) | |
download | pysnmp-627d9ff4a3715477e56fe397f099ad0db0d5c1b9.tar.gz |
* Asyncore and asyncio-based APIs reworked to become functions.
* Asyncio and Twisted API moved entirely into high-level domain to
be aligned with other high-level APIs. This WILL BREAK backward
compatibility for those apps that use Twisted API.
Diffstat (limited to 'pysnmp')
28 files changed, 2184 insertions, 1133 deletions
diff --git a/pysnmp/carrier/twisted/dgram/udp.py b/pysnmp/carrier/twisted/dgram/udp.py index d90d93b..82e2d2b 100644 --- a/pysnmp/carrier/twisted/dgram/udp.py +++ b/pysnmp/carrier/twisted/dgram/udp.py @@ -14,14 +14,16 @@ class UdpTwistedTransport(DgramTwistedTransport): # AbstractTwistedTransport API - def openClientMode(self, iface=('', 0)): + def openClientMode(self, iface=None): + if iface is None: + iface = ('', 0) try: self._lport = reactor.listenUDP(iface[1], self, iface[0]) except Exception: raise error.CarrierError(sys.exc_info()[1]) return self - def openServerMode(self, iface=('', 161)): + def openServerMode(self, iface): try: self._lport = reactor.listenUDP(iface[1], self, iface[0]) except Exception: diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index 5c1bd83..05941b8 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -326,6 +326,7 @@ def addTransport(snmpEngine, transportDomain, transport): ) # here we note that we have created transportDispatcher automatically snmpEngine.setUserContext(automaticTransportDispatcher=0) + snmpEngine.transportDispatcher.registerTransport( transportDomain, transport ) diff --git a/pysnmp/entity/rfc3413/asyncio/__init__.py b/pysnmp/entity/rfc3413/asyncio/__init__.py deleted file mode 100644 index ac0b2c0..0000000 --- a/pysnmp/entity/rfc3413/asyncio/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package.
diff --git a/pysnmp/entity/rfc3413/asyncio/cmdgen.py b/pysnmp/entity/rfc3413/asyncio/cmdgen.py deleted file mode 100644 index 9e8d603..0000000 --- a/pysnmp/entity/rfc3413/asyncio/cmdgen.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright (C) 2014, Zebra Technologies -# Authors: Matt Hooks <me@matthooks.com> -# Zachary Lorusso <zlorusso@gmail.com> -# Modified by Ilya Etingof <ilya@snmplabs.com> -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -# THE POSSIBILITY OF SUCH DAMAGE. -# -from pysnmp.entity.rfc3413 import cmdgen -from pyasn1.compat.octets import null -from pysnmp.proto.api import v2c -try: - import asyncio -except ImportError: - import trollius as asyncio - -getNextVarBinds = cmdgen.getNextVarBinds - -class AbstractCommandGenerator: - commandGenerator = None - - def _cbFunWithFuture(self, snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, varBinds, future): - if future.cancelled(): - return - future.set_result( - (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds) - ) - - def sendVarBinds(self, snmpEngine, targetName, - contextEngineId, contextName, varBinds): - future = asyncio.Future() - self.commandGenerator.sendVarBinds( - snmpEngine, - targetName, - contextEngineId, - contextName, - varBinds, - self._cbFunWithFuture, - future - ) - return future - -class GetCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.GetCommandGenerator() - -class SetCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.SetCommandGenerator() - -class NextCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.NextCommandGenerator() - -class BulkCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.BulkCommandGenerator() - - def sendVarBinds(self, snmpEngine, targetName, - contextEngineId, contextName, - nonRepeaters, maxRepetitions, varBinds): - future = asyncio.Future() - self.commandGenerator.sendVarBinds( - snmpEngine, - targetName, - contextEngineId, - contextName, - nonRepeaters, - maxRepetitions, - varBinds, - self._cbFunWithFuture, - future - ) - return future diff --git a/pysnmp/entity/rfc3413/asyncio/ntforg.py b/pysnmp/entity/rfc3413/asyncio/ntforg.py deleted file mode 100644 index 03e927d..0000000 --- a/pysnmp/entity/rfc3413/asyncio/ntforg.py +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright (C) 2014, Zebra Technologies -# Authors: Matt Hooks <me@matthooks.com> -# Zachary Lorusso <zlorusso@gmail.com> -# Modified by Ilya Etingof <ilya@snmplabs.com> -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -# THE POSSIBILITY OF SUCH DAMAGE. -# -from pysnmp.entity.rfc3413 import ntforg -from pyasn1.compat.octets import null -try: - import asyncio -except ImportError: - import trollius as asyncio - -def _cbFunWithFuture(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, varBinds, future): - if future.cancelled(): - return - future.set_result( - (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds) - ) - -class NotificationOriginator: - def __init__(self): - self.notificationOriginator = ntforg.NotificationOriginator() - - def sendVarBinds(self, - snmpEngine, - notificationTarget, - snmpContext, - contextName, - notificationName, - instanceIndex, - additionalVarBinds=()): - future = asyncio.Future() - self.notificationOriginator.sendVarBinds( - snmpEngine, - notificationTarget, - snmpContext, - contextName, - notificationName, - instanceIndex, - additionalVarBinds, - _cbFunWithFuture, - future - ) - return future diff --git a/pysnmp/entity/rfc3413/twisted/__init__.py b/pysnmp/entity/rfc3413/twisted/__init__.py deleted file mode 100644 index 8c3066b..0000000 --- a/pysnmp/entity/rfc3413/twisted/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/pysnmp/entity/rfc3413/twisted/cmdgen.py b/pysnmp/entity/rfc3413/twisted/cmdgen.py deleted file mode 100644 index 40f5464..0000000 --- a/pysnmp/entity/rfc3413/twisted/cmdgen.py +++ /dev/null @@ -1,136 +0,0 @@ -from twisted.internet import defer -from pysnmp.entity.rfc3413 import cmdgen - -def _cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, varBinds, cbCtx): - df = cbCtx['df'] - df.callback( - (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds) - ) - # Callback function may return another deferred to indicate - # it wishes to continue MIB walk. - if isinstance(df.result, defer.Deferred): - cbCtx['df'] = df.result - return 1 # continue walking - -class AbstractCommandGenerator: - commandGenerator = None - - def sendVarBinds(self, snmpEngine, targetName, - contextEngineId, contextName, varBinds): - df = defer.Deferred() - self.commandGenerator.sendVarBinds( - snmpEngine, - targetName, - contextEngineId, - contextName, - varBinds, - _cbFun, - { 'df': df } # anonymous dictionary used for cbCtx - ) - return df - -class GetCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.GetCommandGenerator() - -class SetCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.SetCommandGenerator() - -class NextCommandGeneratorSingleRun(AbstractCommandGenerator): - commandGenerator = cmdgen.NextCommandGeneratorSingleRun() - -class NextCommandGenerator(AbstractCommandGenerator): - commandGenerator = cmdgen.NextCommandGenerator() - -class AbstractBulkCommandGenerator: - commandGenerator = None - - def sendVarBinds( - self, - snmpEngine, - targetName, - contextEngineId, - contextName, - nonRepeaters, - maxRepetitions, - varBinds - ): - df = defer.Deferred() - self.commandGenerator.sendVarBinds( - snmpEngine, - targetName, - contextEngineId, - contextName, - nonRepeaters, - maxRepetitions, - varBinds, - _cbFun, - { 'df': df } # anonymous dictionary used for cbCtx - ) - return df - -class BulkCommandGeneratorSingleRun(AbstractBulkCommandGenerator): - commandGenerator = cmdgen.BulkCommandGeneratorSingleRun() - -class BulkCommandGenerator(AbstractBulkCommandGenerator): - commandGenerator = cmdgen.BulkCommandGenerator() - -# -# Obsolete, compatibility interfaces. -# - -def __sendReqCbFun(response, outerDf): - ( snmpEngine, - errorIndication, - errorStatus, - errorIndex, - varBinds) = response - outerDf.callback((errorIndication, errorStatus, errorIndex, varBinds)) - # Callback function may return another deferred to indicate - # it wishes to continue MIB walk. - if isinstance(outerDf.result, defer.Deferred): - innerDf = defer.Deferred() - innerDf.addCallback(__sendReqCbFun, outerDf.result) - return innerDf - -def _sendReq(self, - snmpEngine, - targetName, - varBinds, - contextEngineId=None, - contextName=''): - innerDf = self.sendVarBinds(snmpEngine, - targetName, - contextEngineId, - contextName, - varBinds) - outerDf = defer.Deferred() - innerDf.addCallback(__sendReqCbFun, outerDf) - return outerDf - -def _sendBulkReq(self, - snmpEngine, - targetName, - nonRepeaters, - maxRepetitions, - varBinds, - contextEngineId=None, - contextName=''): - innerDf = self.sendVarBinds(snmpEngine, - targetName, - contextEngineId, - contextName, - nonRepeaters, - maxRepetitions, - varBinds) - outerDf = defer.Deferred() - innerDf.addCallback(__sendReqCbFun, outerDf) - return outerDf - -# install compatibility wrappers -GetCommandGenerator.sendReq = _sendReq -SetCommandGenerator.sendReq = _sendReq -NextCommandGenerator.sendReq = _sendReq -NextCommandGeneratorSingleRun.sendReq = _sendReq -BulkCommandGenerator.sendReq = _sendBulkReq -BulkCommandGeneratorSingleRun.sendReq = _sendBulkReq diff --git a/pysnmp/entity/rfc3413/twisted/ntforg.py b/pysnmp/entity/rfc3413/twisted/ntforg.py deleted file mode 100644 index cc796b6..0000000 --- a/pysnmp/entity/rfc3413/twisted/ntforg.py +++ /dev/null @@ -1,75 +0,0 @@ -from twisted.internet import defer -from pysnmp.entity.rfc3413 import ntforg -from pyasn1.compat.octets import null - -def __cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, varBinds, cbCtx): - cbCtx.callback( - (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds) - ) - -class NotificationOriginator: - def __init__(self, snmpContext=None): - self.snmpContext = snmpContext # this is deprecated - self.notificationOriginator = ntforg.NotificationOriginator() - - def sendVarBinds(self, - snmpEngine, - notificationTarget, - snmpContext, - contextName, - notificationName, - instanceIndex, - additionalVarBinds=()): - df = defer.Deferred() - self.notificationOriginator.sendVarBinds( - snmpEngine, - notificationTarget, - snmpContext, - contextName, - notificationName, - instanceIndex, - additionalVarBinds, - __cbFun, - df - ) - return df - -# -# Obsolete, compatibility interfaces. -# - -def __sendReqCbFun(response, outerDf): - ( snmpEngine, - errorIndication, - errorStatus, - errorIndex, - varBinds) = response - outerDf.callback((errorIndication, errorStatus, errorIndex, varBinds)) - # Callback function may return another deferred to indicate - # it wishes to continue MIB walk. - if isinstance(outerDf.result, defer.Deferred): - innerDf = defer.Deferred() - innerDf.addCallback(__sendReqCbFun, outerDf.result) - return innerDf - -def _sendNotification(self, - snmpEngine, - notificationTarget, - notificationName, - additionalVarBinds=None, - contextName=null): - - innerDf = self.sendVarBinds(snmpEngine, - notificationTarget, - self.snmpContext, - contextName, - notificationName, - None, - additionalVarBinds) - outerDf = defer.Deferred() - innerDf.addCallback(__sendReqCbFun, outerDf) - return outerDf - -# install compatibility wrappers -NotificationOriginator.sendNotification = _sendNotification diff --git a/pysnmp/hlapi/__init__.py b/pysnmp/hlapi/__init__.py index 7289fb6..3f8bee9 100644 --- a/pysnmp/hlapi/__init__.py +++ b/pysnmp/hlapi/__init__.py @@ -3,3 +3,6 @@ from pysnmp.smi.rfc1902 import * from pysnmp.hlapi.auth import * from pysnmp.hlapi.context import * from pysnmp.entity.engine import * + +# default is synchronous asyncore-based API +from pysnmp.hlapi.asyncore._sync import * diff --git a/pysnmp/hlapi/asyncio/__init__.py b/pysnmp/hlapi/asyncio/__init__.py new file mode 100644 index 0000000..9ec0fdf --- /dev/null +++ b/pysnmp/hlapi/asyncio/__init__.py @@ -0,0 +1,8 @@ +from pysnmp.proto.rfc1902 import * +from pysnmp.smi.rfc1902 import * +from pysnmp.entity.engine import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.asyncio.transport import * +from pysnmp.hlapi.asyncio.cmdgen import * +from pysnmp.hlapi.asyncio.ntforg import * diff --git a/pysnmp/hlapi/asyncio/cmdgen.py b/pysnmp/hlapi/asyncio/cmdgen.py new file mode 100644 index 0000000..a1610bc --- /dev/null +++ b/pysnmp/hlapi/asyncio/cmdgen.py @@ -0,0 +1,479 @@ +# +# Copyright (C) 2014, Zebra Technologies +# Authors: Matt Hooks <me@matthooks.com> +# Zachary Lorusso <zlorusso@gmail.com> +# Modified by Ilya Etingof <ilya@snmplabs.com> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.asyncio.transport import * +from pysnmp.entity.rfc3413 import cmdgen +try: + import asyncio +except ImportError: + import trollius as asyncio + +__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib'] + +vbProcessor = CommandGeneratorVarBinds() +lcd = CommandGeneratorLcdConfigurator() + +isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1] + +@asyncio.coroutine +def getCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform SNMP GET query. + + When itereator gets advanced by :py:mod:`asyncio` main loop, + SNMP GET request is send (:RFC:`1905#section-4.2.1`). + The iterator yields :py:class:`asyncio.Future` which gets done whenever + response arrives or error occurs. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> import asyncio + >>> from pysnmp.hlapi.asyncio import * + >>> + >>> @asyncio.coroutine + ... def run(): + ... errorIndication, errorStatus, errorIndex, varBinds = yield from getCmd( + ... SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)) + ... ) + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> asyncio.get_event_loop().run_until_complete(run()) + (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'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, future = cbCtx + if future.cancelled(): + return + future.set_result( + (errorIndication, errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + future = asyncio.Future() + + cmdgen.GetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), future) + ) + return future + +@asyncio.coroutine +def setCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform SNMP SET query. + + When itereator gets advanced by :py:mod:`asyncio` main loop, + SNMP SET request is send (:RFC:`1905#section-4.2.5`). + The iterator yields :py:class:`asyncio.Future` which gets done whenever + response arrives or error occurs. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> import asyncio + >>> from pysnmp.hlapi.asyncio import * + >>> + >>> @asyncio.coroutine + ... def run(): + ... errorIndication, errorStatus, errorIndex, varBinds = yield from setCmd( + ... SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') + ... ) + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> asyncio.get_event_loop().run_until_complete(run()) + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('Linux i386'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, future = cbCtx + if future.cancelled(): + return + future.set_result( + (errorIndication, errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + future = asyncio.Future() + + cmdgen.SetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), future) + ) + return future + +@asyncio.coroutine +def nextCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform SNMP GETNEXT query. + + When itereator gets advanced by :py:mod:`asyncio` main loop, + SNMP GETNEXT request is send (:RFC:`1905#section-4.2.2`). + The iterator yields :py:class:`asyncio.Future` which gets done whenever + response arrives or error occurs. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Response to GETNEXT always contain + a single row. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> import asyncio + >>> from pysnmp.hlapi.asyncio import * + >>> + >>> @asyncio.coroutine + ... def run(): + ... errorIndication, errorStatus, errorIndex, varBinds = yield from nextCmd( + ... SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')) + ... ) + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> asyncio.get_event_loop().run_until_complete(run()) + (None, 0, 0, [[ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('Linux i386'))]]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, future = cbCtx + if future.cancelled(): + return + future.set_result( + (errorIndication, errorStatus, errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ]) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + future = asyncio.Future() + + cmdgen.NextCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), future) + ) + return future + +@asyncio.coroutine +def bulkCmd(snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, *varBinds, **options): + """Creates a generator to perform SNMP GETBULK query. + + When itereator gets advanced by :py:mod:`asyncio` main loop, + SNMP GETBULK request is send (:RFC:`1905#section-4.2.3`). + The iterator yields :py:class:`asyncio.Future` which gets done whenever + response arrives or error occurs. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + nonRepeaters : int + One MIB variable is requested in response for the first + `nonRepeaters` MIB variables in request. + + maxRepetitions : int + `maxRepetitions` MIB variables are requested in response for each + of the remaining MIB variables in the request (e.g. excluding + `nonRepeaters`). Remote SNMP engine may choose lesser value than + requested. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Response to GETNEXT always contain + a single row. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> import asyncio + >>> from pysnmp.hlapi.asyncio import * + >>> + >>> @asyncio.coroutine + ... def run(): + ... errorIndication, errorStatus, errorIndex, varBinds = yield from nextCmd( + ... SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... 0, 2, + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')) + ... ) + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> asyncio.get_event_loop().run_until_complete(run()) + (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')), ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1')]]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, future = cbCtx + if future.cancelled(): + return + future.set_result( + (errorIndication, errorStatus, errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ]) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + future = asyncio.Future() + + cmdgen.BulkCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + nonRepeaters, + maxRepetitions, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), future) + ) + return future diff --git a/pysnmp/hlapi/asyncio/ntforg.py b/pysnmp/hlapi/asyncio/ntforg.py new file mode 100644 index 0000000..5f2d10b --- /dev/null +++ b/pysnmp/hlapi/asyncio/ntforg.py @@ -0,0 +1,172 @@ +# +# Copyright (C) 2014, Zebra Technologies +# Authors: Matt Hooks <me@matthooks.com> +# Zachary Lorusso <zlorusso@gmail.com> +# Modified by Ilya Etingof <ilya@snmplabs.com> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.asyncio.transport import * +from pysnmp.entity.rfc3413 import ntforg, context +try: + import asyncio +except ImportError: + import trollius as asyncio + +__all__ = ['sendNotification'] + +vbProcessor = NotificationOriginatorVarBinds() +lcd = NotificationOriginatorLcdConfigurator() + +@asyncio.coroutine +def sendNotification(snmpEngine, authData, transportTarget, contextData, + notifyType, varBinds, **options): + """Creates a generator to send SNMP notification. + + When itereator gets advanced by :py:mod:`asyncio` main loop, + SNMP TRAP or INFORM notification is send (:RFC:`1905#section-4.2.6`). + The iterator yields :py:class:`asyncio.Future` which gets done whenever + response arrives or error occurs. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + notifyType : str + Indicates type of notification to be sent. Recognized literal + values are *trap* or *inform*. + + varBinds: tuple + Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance + representing a minimum sequence of MIB variables required for + particular notification type. + Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` + objects could be passed instead. In the latter case it is up to + the user to ensure proper Notification PDU contents. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `sendNotification` generator will be exhausted immidiately unless + an instance of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class + or a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` `varBinds` + are send back into running generator (supported since Python 2.6). + + Examples + -------- + >>> import asyncio + >>> from pysnmp.hlapi.asyncio import * + >>> + >>> @asyncio.coroutine + ... def run(): + ... errorIndication, errorStatus, errorIndex, varBinds = yield from sendNotification( + ... SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 162)), + ... ContextData(), + ... 'trap', + ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) + ... print(errorIndication, errorStatus, errorIndex, varBinds) + ... + >>> asyncio.get_event_loop().run_until_complete(run()) + (None, 0, 0, []) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, future = cbCtx + if future.cancelled(): + return + future.set_result( + (errorIndication, errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + notifyName = lcd.configure( + snmpEngine, authData, transportTarget, notifyType + ) + + future = asyncio.Future() + + ntforg.NotificationOriginator().sendVarBinds( + snmpEngine, + notifyName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), future) + ) + + if notifyType == 'trap': + def __trapFun(future): + if future.cancelled(): + return + future.set_result((None, 0, 0, [])) + + loop = asyncio.get_event_loop() + loop.call_soon(__trapFun, future) + + return future diff --git a/pysnmp/hlapi/asyncio/transport.py b/pysnmp/hlapi/asyncio/transport.py new file mode 100644 index 0000000..6376039 --- /dev/null +++ b/pysnmp/hlapi/asyncio/transport.py @@ -0,0 +1,109 @@ +import socket, sys +from pysnmp.carrier.asyncio.dgram import udp, udp6 +from pysnmp.hlapi.transport import AbstractTransportTarget + +__all__ = ['Udp6TransportTarget', 'UdpTransportTarget'] + +class UdpTransportTarget(AbstractTransportTarget): + """Creates UDP/IPv4 configuration entry and initialize socket API if needed. + + This object can be used for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine` + class instance. + + See :RFC:`1906#section-3` for more information on the UDP transport mapping. + + Parameters + ---------- + transportAddr : tuple + Indicates remote address in Python :py:mod:`socket` module format + which is a tuple of FQDN, port where FQDN is a string representing + either hostname or IPv4 address in quad-dotted form, port is an + integer. + timeout : int + Response timeout in seconds. + retries : int + Maximum number of request retries, 0 retries means just a single + request. + tagList : str + Arbitrary string that contains a list of tag values which are used + to select target addresses for a particular operation + (:RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.hlapi.asyncio import UdpTransportTarget + >>> UdpTransportTarget(('demo.snmplabs.com', 161)) + UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='') + >>> + + """ + transportDomain = udp.domainName + protoTransport = udp.UdpAsyncioTransport + def _resolveAddr(self, transportAddr): + try: + return socket.getaddrinfo(transportAddr[0], + transportAddr[1], + socket.AF_INET, + socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror: + raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) + +class Udp6TransportTarget(AbstractTransportTarget): + """Creates UDP/IPv6 configuration entry and initialize socket API if needed. + + This object can be used by + :py:class:`~pysnmp.hlapi.asyncio.AsyncCommandGenerator` or + :py:class:`~pysnmp.hlapi.asyncio.AsyncNotificationOriginator` + and their derevatives for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine` + class instance. + + See :RFC:`1906#section-3`, :RFC:`2851#section-4` for more information + on the UDP and IPv6 transport mapping. + + Parameters + ---------- + transportAddr : tuple + Indicates remote address in Python :py:mod:`socket` module format + which is a tuple of FQDN, port where FQDN is a string representing + either hostname or IPv6 address in one of three conventional forms + (:RFC:`1924#section-3`), port is an integer. + timeout : int + Response timeout in seconds. + retries : int + Maximum number of request retries, 0 retries means just a single + request. + tagList : str + Arbitrary string that contains a list of tag values which are used + to select target addresses for a particular operation + (:RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.hlapi.asyncio import Udp6TransportTarget + >>> Udp6TransportTarget(('google.com', 161)) + Udp6TransportTarget(('2a00:1450:4014:80a::100e', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 161)) + Udp6TransportTarget(('fedc:ba98:7654:3210:fedc:ba98:7654:3210', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('1080:0:0:0:8:800:200C:417A', 161)) + Udp6TransportTarget(('1080::8:800:200c:417a', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('::0', 161)) + Udp6TransportTarget(('::', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('::', 161)) + Udp6TransportTarget(('::', 161), timeout=1, retries=5, tagList='') + >>> + + """ + transportDomain = udp6.domainName + protoTransport = udp6.Udp6AsyncioTransport + def _resolveAddr(self, transportAddr): + try: + return socket.getaddrinfo(transportAddr[0], + transportAddr[1], + socket.AF_INET6, + socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror: + raise error.PySnmpError('Bad IPv6/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) diff --git a/pysnmp/hlapi/asyncore/__init__.py b/pysnmp/hlapi/asyncore/__init__.py index 9831a39..a6d2ece 100644 --- a/pysnmp/hlapi/asyncore/__init__.py +++ b/pysnmp/hlapi/asyncore/__init__.py @@ -6,10 +6,3 @@ from pysnmp.hlapi.asyncore.transport import * from pysnmp.hlapi.asyncore.cmdgen import * from pysnmp.hlapi.asyncore.ntforg import * from pysnmp.entity.engine import * - -try: - from pysnmp.hlapi.asyncore._sync.cmdgen import * - from pysnmp.hlapi.asyncore._sync.ntforg import * -except SyntaxError: - from pysnmp.hlapi.asyncore._sync.compat.cmdgen import * - from pysnmp.hlapi.asyncore._sync.compat.ntforg import * diff --git a/pysnmp/hlapi/asyncore/_sync/__init__.py b/pysnmp/hlapi/asyncore/_sync/__init__.py new file mode 100644 index 0000000..2a14fd2 --- /dev/null +++ b/pysnmp/hlapi/asyncore/_sync/__init__.py @@ -0,0 +1,13 @@ +from pysnmp.proto.rfc1902 import * +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.asyncore.transport import * +from pysnmp.entity.engine import * + +try: + from pysnmp.hlapi.asyncore._sync.cmdgen import * + from pysnmp.hlapi.asyncore._sync.ntforg import * +except SyntaxError: + from pysnmp.hlapi.asyncore._sync.compat.cmdgen import * + from pysnmp.hlapi.asyncore._sync.compat.ntforg import * diff --git a/pysnmp/hlapi/asyncore/_sync/cmdgen.py b/pysnmp/hlapi/asyncore/_sync/cmdgen.py index 36da95c..5cb8ab4 100644 --- a/pysnmp/hlapi/asyncore/_sync/cmdgen.py +++ b/pysnmp/hlapi/asyncore/_sync/cmdgen.py @@ -1,7 +1,7 @@ -from pysnmp.hlapi.asyncore.cmdgen import * +from pysnmp.hlapi.asyncore import cmdgen from pysnmp.hlapi.varbinds import * from pysnmp.proto.rfc1905 import endOfMibView -from pysnmp.proto.errind import * +from pysnmp.proto import errind from pyasn1.type.univ import Null __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd'] @@ -86,17 +86,15 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - cmdGen = AsyncCommandGenerator() - while True: if varBinds: - cmdGen.getCmd( + cmdgen.getCmd( snmpEngine, authData, transportTarget, contextData, varBinds, - (cbFun, cbCtx), + cbFun, cbCtx, options.get('lookupMib', True) ) @@ -196,17 +194,15 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - cmdGen = AsyncCommandGenerator() - while True: if varBinds: - cmdGen.setCmd( + cmdgen.setCmd( snmpEngine, authData, transportTarget, contextData, varBinds, - (cbFun, cbCtx), + cbFun, cbCtx, options.get('lookupMib', True) ) @@ -335,20 +331,18 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, vbProcessor = CommandGeneratorVarBinds() - cmdGen = AsyncCommandGenerator() - initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] totalRows = totalCalls = 0 while True: if varBinds: - cmdGen.nextCmd(snmpEngine, + cmdgen.nextCmd(snmpEngine, authData, transportTarget, contextData, [ (x[0], Null()) for x in varBinds ], - (cbFun, cbCtx), + cbFun, cbCtx, lookupMib) snmpEngine.transportDispatcher.runDispatcher() @@ -525,8 +519,6 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, vbProcessor = CommandGeneratorVarBinds() - cmdGen = AsyncCommandGenerator() - initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] nullVarBinds = [ False ] * len(initialVars) @@ -537,13 +529,13 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, if maxRows and totalRows < maxRows: maxRepetitions = min(maxRepetitions, maxRows-totalRows) - cmdGen.bulkCmd(snmpEngine, + cmdgen.bulkCmd(snmpEngine, authData, transportTarget, contextData, nonRepeaters, maxRepetitions, [ (x[0], Null()) for x in varBinds ], - (cbFun, cbCtx), + cbFun, cbCtx, lookupMib) snmpEngine.transportDispatcher.runDispatcher() diff --git a/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py b/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py index 530c376..701cb5f 100644 --- a/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py +++ b/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py @@ -1,10 +1,10 @@ # # This is a Python 2.6- version of the same file at level up # -from pysnmp.hlapi.asyncore.cmdgen import * +from pysnmp.hlapi.asyncore import cmdgen from pysnmp.hlapi.varbinds import * from pysnmp.proto.rfc1905 import endOfMibView -from pysnmp.proto.errind import * +from pysnmp.proto import errind from pyasn1.type.univ import Null __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'next'] @@ -25,16 +25,14 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - cmdGen = AsyncCommandGenerator() - if varBinds: - cmdGen.getCmd( + cmdgen.getCmd( snmpEngine, authData, transportTarget, contextData, varBinds, - (cbFun, cbCtx), + cbFun, cbCtx, options.get('lookupMib', True) ) @@ -63,16 +61,14 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - cmdGen = AsyncCommandGenerator() - while True: - cmdGen.setCmd( + cmdgen.setCmd( snmpEngine, authData, transportTarget, contextData, varBinds, - (cbFun, cbCtx), + cbFun, cbCtx, options.get('lookupMib', True) ) @@ -106,19 +102,17 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, vbProcessor = CommandGeneratorVarBinds() - cmdGen = AsyncCommandGenerator() - initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] totalRows = totalCalls = 0 while True: - cmdGen.nextCmd(snmpEngine, + cmdgen.nextCmd(snmpEngine, authData, transportTarget, contextData, [ (x[0], Null()) for x in varBinds ], - (cbFun, cbCtx), + cbFun, cbCtx, lookupMib) snmpEngine.transportDispatcher.runDispatcher() @@ -183,8 +177,6 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, vbProcessor = CommandGeneratorVarBinds() - cmdGen = AsyncCommandGenerator() - initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] nullVarBinds = [ False ] * len(initialVars) @@ -195,13 +187,13 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, if maxRows and totalRows < maxRows: maxRepetitions = min(maxRepetitions, maxRows-totalRows) - cmdGen.bulkCmd(snmpEngine, + cmdgen.bulkCmd(snmpEngine, authData, transportTarget, contextData, nonRepeaters, maxRepetitions, [ (x[0], Null()) for x in varBinds ], - (cbFun, cbCtx), + cbFun, cbCtx, lookupMib) snmpEngine.transportDispatcher.runDispatcher() diff --git a/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py b/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py index 420b3b6..92b32b3 100644 --- a/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py +++ b/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py @@ -1,7 +1,7 @@ # # This is a Python 2.6- version of the same file at level up # -from pysnmp.hlapi.asyncore.ntforg import * +from pysnmp.hlapi.asyncore import ntforg __all__ = ['sendNotification', 'next'] @@ -25,17 +25,15 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - ntfOrg = AsyncNotificationOriginator() - if varBinds: - ntfOrg.sendNotification( + ntforg.sendNotification( snmpEngine, authData, transportTarget, contextData, notifyType, varBinds, - (cbFun, cbCtx), + cbFun, cbCtx, options.get('lookupMib', True) ) diff --git a/pysnmp/hlapi/asyncore/_sync/ntforg.py b/pysnmp/hlapi/asyncore/_sync/ntforg.py index ac778c1..e43a974 100644 --- a/pysnmp/hlapi/asyncore/_sync/ntforg.py +++ b/pysnmp/hlapi/asyncore/_sync/ntforg.py @@ -1,4 +1,4 @@ -from pysnmp.hlapi.asyncore.ntforg import * +from pysnmp.hlapi.asyncore import ntforg __all__ = ['sendNotification'] @@ -93,18 +93,16 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, cbCtx = {} - ntfOrg = AsyncNotificationOriginator() - while True: if varBinds: - ntfOrg.sendNotification( + ntforg.sendNotification( snmpEngine, authData, transportTarget, contextData, notifyType, varBinds, - cbInfo=(cbFun, cbCtx), + cbFun, cbCtx, lookupMib=options.get('lookupMib', True) ) diff --git a/pysnmp/hlapi/asyncore/cmdgen.py b/pysnmp/hlapi/asyncore/cmdgen.py index 28c5954..b9be41b 100644 --- a/pysnmp/hlapi/asyncore/cmdgen.py +++ b/pysnmp/hlapi/asyncore/cmdgen.py @@ -10,520 +10,491 @@ from pysnmp.hlapi.asyncore.transport import * from pysnmp.proto import rfc1905, errind from pyasn1.type import univ, base -__all__ = ['AsyncCommandGenerator'] - -class AsyncCommandGenerator: - """Creates asyncore-based SNMP Command Generator object. - - This is a high-level wrapper around pure Command Generator - impementation that aims at simplyfing - :py:class:`pysnmp.hlapi.SnmpEngine`'s Local Configuration - Datastore (:RFC:`2271#section-3.4.2`) management. Typically, - users instantiate `AsyncCommandGenerator` and call its - commmand-specific methods passing them canned Security, - Transport and SNMP Context parameters along with - :py:class:`~pysnmp.smi.rfc1902.ObjectType` object carrying - MIB variables to include with SNMP request. `AsyncCommandGenerator` - will manage LCD by applying user-supplied configuratoin parameters - and running requested operation. - - See :RFC:`3413#section-3.1` for more information on SNMP - Command Generator purpose, design and supported operations. +__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib'] + +vbProcessor = CommandGeneratorVarBinds() +lcd = CommandGeneratorLcdConfigurator() + +isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1] + +def getCmd(snmpEngine, authData, transportTarget, contextData, + varBinds, cbFun=None, cbCtx=None, lookupMib=True): + """Performs SNMP GET query. + + Based on passed parameters, prepares SNMP GET packet + (:RFC:`1905#section-4.2.1`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + Other Parameters + ---------------- + cbFun : callable + user-supplied callable that is invoked to pass SNMP response + data or error to user at a later point of time. + cbCtx : object + user-supplied object passing additional parameters to/from + `cbFun`. + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.hlapi.asyncore import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> getCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... [ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))], + ... cbFun=cbFun) + >>> snmpEngine.transportDispatcher.runDispatcher() + (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'))]) + >>> """ - vbProcessor = CommandGeneratorVarBinds() - lcd = CommandGeneratorLcdConfigurator() - - def getCmd(self, snmpEngine, authData, transportTarget, contextData, - varBinds, cbInfo, lookupMib=True): - """Performs SNMP GET query. - - Based on passed parameters, prepares SNMP GET packet - (:RFC:`1905#section-4.2.1`) and schedules its transmission by - I/O framework at a later point of time. - - Parameters - ---------- - snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` - Class instance representing SNMP engine. - - authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` - Class instance representing SNMP credentials. - - transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` - Class instance representing transport type along with SNMP peer - address. - - contextData : :py:class:`~pysnmp.hlapi.ContextData` - Class instance representing SNMP ContextEngineId and ContextName - values. - - varBinds : tuple - A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class - instances representing MIB variables to place into SNMP request. - - cbInfo : tuple - - * `cbFun` - user-supplied callable that is invoked to pass - SNMP response data or error to user at a later point of time. - * `cbCtx` - user-supplied object passing additional parameters - to/from `cbFun`. Default is `None`. - - Other Parameters - ---------------- - lookupMib : bool - `lookupMib` - load MIB and resolve response MIB variables at - the cost of slightly reduced performance. Default is `True`. - - Notes - ----- - User-supplied `cbFun` callable must have the following call - signature: - - * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): - Class instance representing SNMP engine. - * sendRequestHandle (int): Unique request identifier. Can be used - for matching multiple ongoing requests with received responses. - * errorIndication (str): True value indicates SNMP engine error. - * errorStatus (str): True value indicates SNMP PDU error. - * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` - * varBinds (tuple): A sequence of - :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances - representing MIB variables returned in SNMP response in exactly - the same order as `varBinds` in request. - * `cbCtx` : Original user-supplied object. - - Returns - ------- - sendRequestHandle : int - Unique request identifier. Can be used for matching received - responses with ongoing requests. - - Raises - ------ - PySnmpError - Or its derivative indicating that an error occurred while - performing SNMP operation. - - Examples - -------- - >>> from pysnmp.hlapi.asyncore import * - >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): - ... print(errorIndication, errorStatus, errorIndex, varBinds) - >>> - >>> snmpEngine = SnmpEngine() - >>> g = AsyncCommandGenerator() - >>> g.getCmd(snmpEngine, - ... CommunityData('public'), - ... UdpTransportTarget(('demo.snmplabs.com', 161)), - ... ContextData(), - ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)), - ... (cbFun, None)) - >>> snmpEngine.transportDispatcher.runDispatcher() - (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'))]) - >>> - - """ - def __cbFun(snmpEngine, sendRequestHandle, - errorIndication, errorStatus, errorIndex, - varBinds, cbCtx): - lookupMib, cbFun, cbCtx = cbCtx - return cbFun( - snmpEngine, - sendRequestHandle, - errorIndication, - errorStatus, - errorIndex, - self.vbProcessor.unmakeVarBinds( - snmpEngine, varBinds, lookupMib - ), - cbCtx - ) - - (cbFun, cbCtx) = cbInfo - addrName, paramsName = self.lcd.configure( - snmpEngine, authData, transportTarget - ) - - return cmdgen.GetCommandGenerator().sendVarBinds( + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( snmpEngine, - addrName, - contextData.contextEngineId, - contextData.contextName, - self.vbProcessor.makeVarBinds(snmpEngine, varBinds), - __cbFun, - (lookupMib, cbFun, cbCtx) - ) - - def setCmd(self, snmpEngine, authData, transportTarget, contextData, - varBinds, cbInfo, lookupMib=True): - """Performs SNMP SET query. - - Based on passed parameters, prepares SNMP SET packet - (:RFC:`1905#section-4.2.5`) and schedules its transmission by - I/O framework at a later point of time. - - Parameters - ---------- - snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` - Class instance representing SNMP engine. - - authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` - Class instance representing SNMP credentials. - - transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` - Class instance representing transport type along with SNMP peer - address. - - contextData : :py:class:`~pysnmp.hlapi.ContextData` - Class instance representing SNMP ContextEngineId and ContextName - values. - - varBinds : tuple - A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class - instances representing MIB variables to place into SNMP request. - - cbInfo : tuple - - * `cbFun` - user-supplied callable that is invoked to pass - SNMP response data or error to user at a later point of time. - * `cbCtx` - user-supplied object passing additional parameters - to/from `cbFun`. Default is `None`. - - Other Parameters - ---------------- - lookupMib : bool - `lookupMib` - load MIB and resolve response MIB variables at - the cost of slightly reduced performance. Default is `True`. - - Notes - ----- - User-supplied `cbFun` callable must have the following call - signature: - - * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): - Class instance representing SNMP engine. - * sendRequestHandle (int): Unique request identifier. Can be used - for matching multiple ongoing requests with received responses. - * errorIndication (str): True value indicates SNMP engine error. - * errorStatus (str): True value indicates SNMP PDU error. - * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` - * varBinds (tuple): A sequence of - :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances - representing MIB variables returned in SNMP response in exactly - the same order as `varBinds` in request. - * `cbCtx` : Original user-supplied object. - - Returns - ------- - sendRequestHandle : int - Unique request identifier. Can be used for matching received - responses with ongoing requests. - - Raises - ------ - PySnmpError - Or its derivative indicating that an error occurred while - performing SNMP operation. - - Examples - -------- - >>> from pysnmp.hlapi.asyncore import * - >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): - ... print(errorIndication, errorStatus, errorIndex, varBinds) - >>> - >>> snmpEngine = SnmpEngine() - >>> g = AsyncCommandGenerator() - >>> g.setCmd(snmpEngine, - ... CommunityData('public'), - ... UdpTransportTarget(('demo.snmplabs.com', 161)), - ... ContextData(), - ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysContact', 0), 'info@snmplabs.com'), - ... (cbFun, None)) - >>> snmpEngine.transportDispatcher.runDispatcher() - (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.4.0')), DisplayString('info@snmplabs.com'))]) - >>> - - """ - def __cbFun(snmpEngine, sendRequestHandle, - errorIndication, errorStatus, errorIndex, - varBinds, cbCtx): - lookupMib, cbFun, cbCtx = cbCtx - return cbFun( - snmpEngine, - sendRequestHandle, - errorIndication, - errorStatus, - errorIndex, - self.vbProcessor.unmakeVarBinds( - snmpEngine, varBinds, lookupMib - ), - cbCtx - ) - - (cbFun, cbCtx) = cbInfo - addrName, paramsName = self.lcd.configure( - snmpEngine, authData, transportTarget + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx ) - return cmdgen.SetCommandGenerator().sendVarBinds( + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + return cmdgen.GetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + +def setCmd(snmpEngine, authData, transportTarget, contextData, + varBinds, cbFun=None, cbCtx=None, lookupMib=True): + """Performs SNMP SET query. + + Based on passed parameters, prepares SNMP SET packet + (:RFC:`1905#section-4.2.5`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + Other Parameters + ---------------- + cbFun : callable + user-supplied callable that is invoked to pass SNMP response + data or error to user at a later point of time. + cbCtx : object + user-supplied object passing additional parameters to/from + `cbFun`. + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.hlapi.asyncore import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> setCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... [ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysContact', 0), 'info@snmplabs.com')], + ... cbFun=cbFun) + >>> snmpEngine.transportDispatcher.runDispatcher() + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.4.0')), DisplayString('info@snmplabs.com'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( snmpEngine, - addrName, - contextData.contextEngineId, - contextData.contextName, - self.vbProcessor.makeVarBinds(snmpEngine, varBinds), - __cbFun, - (lookupMib, cbFun, cbCtx) - ) - - def nextCmd(self, snmpEngine, authData, transportTarget, contextData, - varBinds, cbInfo, lookupMib=True): - """Performs SNMP GETNEXT query. - - Based on passed parameters, prepares SNMP GETNEXT packet - (:RFC:`1905#section-4.2.2`) and schedules its transmission by - I/O framework at a later point of time. - - Parameters - ---------- - snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` - Class instance representing SNMP engine. - - authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` - Class instance representing SNMP credentials. - - transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` - Class instance representing transport type along with SNMP peer - address. - - contextData : :py:class:`~pysnmp.hlapi.ContextData` - Class instance representing SNMP ContextEngineId and ContextName - values. - - varBinds : tuple - A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class - instances representing MIB variables to place into SNMP request. - - cbInfo : tuple - - * `cbFun` - user-supplied callable that is invoked to pass - SNMP response data or error to user at a later point of time. - * `cbCtx` - user-supplied object passing additional parameters - to/from `cbFun`. Default is `None`. - - Other Parameters - ---------------- - lookupMib : bool - `lookupMib` - load MIB and resolve response MIB variables at - the cost of slightly reduced performance. Default is `True`. - - Notes - ----- - User-supplied `cbFun` callable must have the following call - signature: - - * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): - Class instance representing SNMP engine. - * sendRequestHandle (int): Unique request identifier. Can be used - for matching multiple ongoing requests with received responses. - * errorIndication (str): True value indicates SNMP engine error. - * errorStatus (str): True value indicates SNMP PDU error. - * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` - * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of - :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances - representing a table of MIB variables returned in SNMP response. - Inner sequences represent table rows and ordered exactly the same - as `varBinds` in request. Response to GETNEXT always contain a - single row. - * `cbCtx` : Original user-supplied object. - - Returns - ------- - sendRequestHandle : int - Unique request identifier. Can be used for matching received - responses with ongoing requests. - - Raises - ------ - PySnmpError - Or its derivative indicating that an error occurred while - performing SNMP operation. - - Examples - -------- - >>> from pysnmp.hlapi.asyncore import * - >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): - ... print(errorIndication, errorStatus, errorIndex, varBinds) - >>> - >>> snmpEngine = SnmpEngine() - >>> g = AsyncCommandGenerator() - >>> g.nextCmd(snmpEngine, - ... CommunityData('public'), - ... UdpTransportTarget(('demo.snmplabs.com', 161)), - ... ContextData(), - ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')), - ... (cbFun, None)) - >>> snmpEngine.transportDispatcher.runDispatcher() - (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'))] ]) - >>> - - """ - def __cbFun(snmpEngine, sendRequestHandle, - errorIndication, errorStatus, errorIndex, - varBindTable, cbCtx): - lookupMib, cbFun, cbCtx = cbCtx - return cbFun( - snmpEngine, - sendRequestHandle, - errorIndication, - errorStatus, - errorIndex, - [ self.vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], - cbCtx - ) - - (cbFun, cbCtx) = cbInfo - addrName, paramsName = self.lcd.configure( - snmpEngine, authData, transportTarget + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx ) - return cmdgen.NextCommandGenerator().sendVarBinds( + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + return cmdgen.SetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + +def nextCmd(snmpEngine, authData, transportTarget, contextData, + varBinds, cbFun=None, cbCtx=None, lookupMib=True): + """Performs SNMP GETNEXT query. + + Based on passed parameters, prepares SNMP GETNEXT packet + (:RFC:`1905#section-4.2.2`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + Other Parameters + ---------------- + cbFun : callable + user-supplied callable that is invoked to pass SNMP response + data or error to user at a later point of time. + cbCtx : object + user-supplied object passing additional parameters to/from + `cbFun`. + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Response to GETNEXT always contain a + single row. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.hlapi.asyncore import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> nextCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... [ObjectType(ObjectIdentity('SNMPv2-MIB', 'system'))], + ... cbFun=cbFun) + >>> snmpEngine.transportDispatcher.runDispatcher() + (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'))] ]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( snmpEngine, - addrName, - contextData.contextEngineId, contextData.contextName, - self.vbProcessor.makeVarBinds(snmpEngine, varBinds), - __cbFun, - (lookupMib, cbFun, cbCtx) + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], + cbCtx ) - def bulkCmd(self, snmpEngine, authData, transportTarget, contextData, - nonRepeaters, maxRepetitions, varBinds, cbInfo, - lookupMib=True): - """Performs SNMP GETBULK query. - - Based on passed parameters, prepares SNMP GETBULK packet - (:RFC:`1905#section-4.2.3`) and schedules its transmission by - I/O framework at a later point of time. - - Parameters - ---------- - snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` - Class instance representing SNMP engine. - - authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` - Class instance representing SNMP credentials. - - transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` - Class instance representing transport type along with SNMP peer - address. - - contextData : :py:class:`~pysnmp.hlapi.ContextData` - Class instance representing SNMP ContextEngineId and ContextName - values. - - nonRepeaters : int - One MIB variable is requested in response for the first - `nonRepeaters` MIB variables in request. - - maxRepetitions : int - `maxRepetitions` MIB variables are requested in response for each - of the remaining MIB variables in the request (e.g. excluding - `nonRepeaters`). Remote SNMP engine may choose lesser value than - requested. - - varBinds : tuple - A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class - instances representing MIB variables to place into SNMP request. - - cbInfo : tuple - - * `cbFun` - user-supplied callable that is invoked to pass - SNMP response data or error to user at a later point of time. - * `cbCtx` - user-supplied object passing additional parameters - to/from `cbFun`. Default is `None`. - - Other Parameters - ---------------- - lookupMib : bool - `lookupMib` - load MIB and resolve response MIB variables at - the cost of slightly reduced performance. Default is `True`. - - Notes - ----- - User-supplied `cbFun` callable must have the following call - signature: - - * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): - Class instance representing SNMP engine. - * sendRequestHandle (int): Unique request identifier. Can be used - for matching multiple ongoing requests with received responses. - * errorIndication (str): True value indicates SNMP engine error. - * errorStatus (str): True value indicates SNMP PDU error. - * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` - * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of - :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances - representing a table of MIB variables returned in SNMP response. - Inner sequences represent table rows and ordered exactly the same - as `varBinds` in request. Number of rows might be less or equal - to `maxRepetitions` value in request. - * `cbCtx` : Original user-supplied object. - - Returns - ------- - sendRequestHandle : int - Unique request identifier. Can be used for matching received - responses with ongoing requests. - - Raises - ------ - PySnmpError - Or its derivative indicating that an error occurred while - performing SNMP operation. - - Examples - -------- - >>> from pysnmp.hlapi.asyncore import * - >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): - ... print(errorIndication, errorStatus, errorIndex, varBinds) - >>> - >>> snmpEngine = SnmpEngine() - >>> g = AsyncCommandGenerator() - >>> g.bulkCmd(snmpEngine, - ... CommunityData('public'), - ... UdpTransportTarget(('demo.snmplabs.com', 161)), - ... ContextData(), - ... 0, 2, - ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')), - ... (cbFun, None)) - >>> snmpEngine.transportDispatcher.runDispatcher() - (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')), ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1')] ]) - >>> - - """ - def __cbFun(snmpEngine, sendRequestHandle, - errorIndication, errorStatus, errorIndex, - varBindTable, cbCtx): - lookupMib, cbFun, cbCtx = cbCtx - return cbFun( - snmpEngine, - sendRequestHandle, - errorIndication, - errorStatus, - errorIndex, - [ self.vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], - cbCtx - ) - - (cbFun, cbCtx) = cbInfo - addrName, paramsName = self.lcd.configure( - snmpEngine, authData, transportTarget - ) - return cmdgen.BulkCommandGenerator().sendVarBinds( + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + return cmdgen.NextCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + +def bulkCmd(snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, varBinds, + cbFun=None, cbCtx=None, lookupMib=True): + """Performs SNMP GETBULK query. + + Based on passed parameters, prepares SNMP GETBULK packet + (:RFC:`1905#section-4.2.3`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + nonRepeaters : int + One MIB variable is requested in response for the first + `nonRepeaters` MIB variables in request. + + maxRepetitions : int + `maxRepetitions` MIB variables are requested in response for each + of the remaining MIB variables in the request (e.g. excluding + `nonRepeaters`). Remote SNMP engine may choose lesser value than + requested. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + Other Parameters + ---------------- + cbFun : callable + user-supplied callable that is invoked to pass SNMP response + data or error to user at a later point of time. + cbCtx : object + user-supplied object passing additional parameters to/from + `cbFun`. + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Number of rows might be less or equal + to `maxRepetitions` value in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.hlapi.asyncore import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> bulkCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... 0, 2, + ... [ObjectType(ObjectIdentity('SNMPv2-MIB', 'system'))], + ... cbFun=cbFun) + >>> snmpEngine.transportDispatcher.runDispatcher() + (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')), ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1')] ]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( snmpEngine, - addrName, - contextData.contextEngineId, - contextData.contextName, - nonRepeaters, maxRepetitions, - self.vbProcessor.makeVarBinds(snmpEngine, varBinds), - __cbFun, - (lookupMib, cbFun, cbCtx) + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], + cbCtx ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + return cmdgen.BulkCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + nonRepeaters, maxRepetitions, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) diff --git a/pysnmp/hlapi/asyncore/ntforg.py b/pysnmp/hlapi/asyncore/ntforg.py index 3565a2f..e250650 100644 --- a/pysnmp/hlapi/asyncore/ntforg.py +++ b/pysnmp/hlapi/asyncore/ntforg.py @@ -6,164 +6,142 @@ from pysnmp.hlapi.context import * from pysnmp.hlapi.lcd import * from pysnmp.hlapi.varbinds import * from pysnmp.hlapi.asyncore.transport import * -from pysnmp.hlapi.asyncore import cmdgen from pysnmp import error -__all__ = ['AsyncNotificationOriginator'] - -class AsyncNotificationOriginator: - """Creates asyncore-based SNMP Notification Originator object. - - This is a high-level wrapper around pure Notification Originator - impementation that aims at simplyfing - :py:class:`pysnmp.hlapi.SnmpEngine`'s Local Configuration - Datastore (:RFC:`2271#section-3.4.2`) management. Typically, - users instantiate `AsyncNotificationOriginator` and call its - commmand-specific methods passing them canned Security, - Transport and SNMP Context parameters along with - :py:class:`~pysnmp.smi.rfc1902.NotificationType` object carrying - MIB variables to include with Notification. `AsyncNotificationOriginator` - will manage LCD by applying user-supplied configuratoin parameters - and running requested operation. - - See :RFC:`3413#section-3.2` for more information on SNMP - Notification Originator purpose, design and supported operations. +__all__ = ['sendNotification'] + +vbProcessor = NotificationOriginatorVarBinds() +lcd = NotificationOriginatorLcdConfigurator() + +def sendNotification(snmpEngine, authData, transportTarget, contextData, + notifyType, varBinds, cbFun=None, cbCtx=None, + lookupMib=False): + """Send SNMP notification. + + Based on passed parameters, prepares SNMP TRAP or INFORM + notification (:RFC:`1905#section-4.2.6`) and schedules its + transmission by I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + notifyType : str + Indicates type of notification to be sent. Recognized literal + values are *trap* or *inform*. + + varBinds: tuple + Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class + instance representing a minimum sequence of MIB variables + required for particular notification type. Alternatively, + a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` + objects could be passed instead. In the latter case it is up to + the user to ensure proper Notification PDU contents. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response to *INFORM* notification or error to user at + a later point of time. The `cbFun` callable is never invoked + for *TRAP* notifications. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + cbFun : callable + user-supplied callable that is invoked to pass SNMP response + to *INFORM* notification or error to user at a later point of + time. The `cbFun` callable is never invoked for *TRAP* notifications. + cbCtx : object + user-supplied object passing additional parameters to/from + `cbFun`. + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing *INFORM* notifications with received + responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing *INFORM* requests. Returns `None` for + *TRAP* notifications. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.hlapi.asyncore import * + >>> + >>> snmpEngine = SnmpEngine() + >>> sendNotification( + ... snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 162)), + ... ContextData(), + ... 'trap', + ... NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')), + ... ) + >>> snmpEngine.transportDispatcher.runDispatcher() + >>> """ - vbProcessor = NotificationOriginatorVarBinds() - lcd = NotificationOriginatorLcdConfigurator() - - def sendNotification(self, snmpEngine, - authData, transportTarget, contextData, - notifyType, - varBinds, - cbInfo=(None, None), - lookupMib=False): - """Send SNMP notification. - - Based on passed parameters, prepares SNMP TRAP or INFORM - notification (:RFC:`1905#section-4.2.6`) and schedules its - transmission by I/O framework at a later point of time. - - Parameters - ---------- - snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` - Class instance representing SNMP engine. - - authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` - Class instance representing SNMP credentials. - - transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget` - Class instance representing transport type along with SNMP peer - address. - - contextData : :py:class:`~pysnmp.hlapi.ContextData` - Class instance representing SNMP ContextEngineId and ContextName - values. - - notifyType : str - Indicates type of notification to be sent. Recognized literal - values are *trap* or *inform*. - - varBinds: tuple - Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class - instance representing a minimum sequence of MIB variables - required for particular notification type. Alternatively, - a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` - objects could be passed instead. In the latter case it is up to - the user to ensure proper Notification PDU contents. - - cbInfo : tuple - - * `cbFun` - user-supplied callable that is invoked to pass - SNMP response to *INFORM* notification or error to user at - a later point of time. The `cbFun` callable is never invoked - for *TRAP* notifications. - * `cbCtx` - user-supplied object passing additional parameters - to/from `cbFun`. Default is `None`. - - Other Parameters - ---------------- - lookupMib : bool - `lookupMib` - load MIB and resolve response MIB variables at - the cost of slightly reduced performance. Default is `True`. - - Notes - ----- - User-supplied `cbFun` callable must have the following call - signature: - - * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): - Class instance representing SNMP engine. - * sendRequestHandle (int): Unique request identifier. Can be used - for matching multiple ongoing *INFORM* notifications with received - responses. - * errorIndication (str): True value indicates SNMP engine error. - * errorStatus (str): True value indicates SNMP PDU error. - * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` - * varBinds (tuple): A sequence of - :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances - representing MIB variables returned in SNMP response in exactly - the same order as `varBinds` in request. - * `cbCtx` : Original user-supplied object. - - Returns - ------- - sendRequestHandle : int - Unique request identifier. Can be used for matching received - responses with ongoing *INFORM* requests. Returns `None` for - *TRAP* notifications. - - Raises - ------ - PySnmpError - Or its derivative indicating that an error occurred while - performing SNMP operation. - - Examples - -------- - >>> from pysnmp.hlapi.asyncore import * - >>> - >>> snmpEngine = SnmpEngine() - >>> n = AsyncNotificationOriginator() - >>> n.sendNotification( - ... snmpEngine, - ... CommunityData('public'), - ... UdpTransportTarget(('demo.snmplabs.com', 162)), - ... ContextData(), - ... 'trap', - ... NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')), - ... ) - >>> snmpEngine.transportDispatcher.runDispatcher() - >>> - - """ - def __cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, varBinds, cbCtx): - lookupMib, cbFun, cbCtx = cbCtx - return cbFun and cbFun( - snmpEngine, - sendRequestHandle, - errorIndication, - errorStatus, errorIndex, - self.vbProcessor.unmakeVarBinds( - snmpEngine, varBinds, lookupMib - ), - cbCtx - ) - - cbFun, cbCtx = cbInfo - - # Create matching transport tags if not given by user - if not transportTarget.tagList: - transportTarget.tagList = str( - hash((authData.securityName, transportTarget.transportAddr)) - ) - if isinstance(authData, CommunityData) and not authData.tag: - authData.tag = transportTarget.tagList.split()[0] - - notifyName = self.lcd.configure( - snmpEngine, authData, transportTarget, notifyType + def __cbFun(snmpEngine, sendRequestHandle, errorIndication, + errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun and cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, errorIndex, + vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx ) - return ntforg.NotificationOriginator().sendVarBinds(snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, self.vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun, (lookupMib, cbFun, cbCtx)) + notifyName = lcd.configure( + snmpEngine, authData, transportTarget, notifyType + ) + + return ntforg.NotificationOriginator().sendVarBinds( + snmpEngine, notifyName, + contextData.contextEngineId, contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, (lookupMib, cbFun, cbCtx) + ) diff --git a/pysnmp/hlapi/asyncore/transport.py b/pysnmp/hlapi/asyncore/transport.py index c585e0c..cadcbb5 100644 --- a/pysnmp/hlapi/asyncore/transport.py +++ b/pysnmp/hlapi/asyncore/transport.py @@ -1,50 +1,13 @@ import socket, sys from pysnmp.carrier.asyncore.dgram import udp, udp6, unix -from pysnmp import error -from pyasn1.compat.octets import null +from pysnmp.hlapi.transport import AbstractTransportTarget __all__ = ['UnixTransportTarget', 'Udp6TransportTarget', 'UdpTransportTarget'] -class _AbstractTransportTarget: - transportDomain = None - protoTransport = NotImplementedError - def __init__(self, transportAddr, timeout=1, retries=5, tagList=null): - self.transportAddr = self._resolveAddr(transportAddr) - self.timeout = timeout - self.retries = retries - self.tagList = tagList - self.iface = None - - def __repr__(self): - return '%s(%r, timeout=%r, retries=%r, tagList=%r)' % ( - self.__class__.__name__, self.transportAddr, - self.timeout, self.retries, self.tagList - ) - - def getTransportInfo(self): - return self.transportDomain, self.transportAddr - - def setLocalAddress(self, iface): - self.iface = iface - return self - - def openClientMode(self): - self.transport = self.protoTransport().openClientMode(self.iface) - return self.transport - - def verifyDispatcherCompatibility(self, snmpEngine): - if not self.protoTransport.isCompatibleWithDispatcher(snmpEngine.transportDispatcher): - raise error.PySnmpError('Transport %r is not compatible with dispatcher %r' % (self.protoTransport, snmpEngine.transportDispatcher)) - - def _resolveAddr(self, transportAddr): raise NotImplementedError() - -class UdpTransportTarget(_AbstractTransportTarget): +class UdpTransportTarget(AbstractTransportTarget): """Creates UDP/IPv4 configuration entry and initialize socket API if needed. - This object can be used by - :py:class:`~pysnmp.hlapi.asyncore.AsyncCommandGenerator` or - :py:class:`~pysnmp.hlapi.asyncore.AsyncNotificationOriginator` - and their derevatives for adding new entries to Local Configuration + This object can be used for adding new entries to Local Configuration Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine` class instance. @@ -87,13 +50,10 @@ class UdpTransportTarget(_AbstractTransportTarget): except socket.gaierror: raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) -class Udp6TransportTarget(_AbstractTransportTarget): +class Udp6TransportTarget(AbstractTransportTarget): """Creates UDP/IPv6 configuration entry and initialize socket API if needed. - This object can be used by - :py:class:`~pysnmp.hlapi.asyncore.AsyncCommandGenerator` or - :py:class:`~pysnmp.hlapi.asyncore.AsyncNotificationOriginator` - and their derevatives for adding new entries to Local Configuration + This object can be used for adding new entries to Local Configuration Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine` class instance. @@ -145,6 +105,6 @@ class Udp6TransportTarget(_AbstractTransportTarget): except socket.gaierror: raise error.PySnmpError('Bad IPv6/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) -class UnixTransportTarget(_AbstractTransportTarget): +class UnixTransportTarget(AbstractTransportTarget): transportDomain = unix.domainName protoTransport = unix.UnixSocketTransport diff --git a/pysnmp/hlapi/lcd.py b/pysnmp/hlapi/lcd.py index 2709ed3..2b62a11 100644 --- a/pysnmp/hlapi/lcd.py +++ b/pysnmp/hlapi/lcd.py @@ -183,6 +183,15 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator): _cmdGenLcdCfg = CommandGeneratorLcdConfigurator() def configure(self, snmpEngine, authData, transportTarget, notifyType): cache = self._getCache(snmpEngine) + + # Create matching transport tags if not given by user. Not good! + if not transportTarget.tagList: + transportTarget.tagList = str( + hash((authData.securityName, transportTarget.transportAddr)) + ) + if isinstance(authData, CommunityData) and not authData.tag: + authData.tag = transportTarget.tagList.split()[0] + addrName, paramsName = self._cmdGenLcdCfg.configure(snmpEngine, authData, transportTarget) tagList = transportTarget.tagList.split() if not tagList: diff --git a/pysnmp/hlapi/transport.py b/pysnmp/hlapi/transport.py new file mode 100644 index 0000000..c836a03 --- /dev/null +++ b/pysnmp/hlapi/transport.py @@ -0,0 +1,37 @@ +from pyasn1.compat.octets import null +from pysnmp import error + +__all__ = [] + +class AbstractTransportTarget: + transportDomain = None + protoTransport = NotImplementedError + def __init__(self, transportAddr, timeout=1, retries=5, tagList=null): + self.transportAddr = self._resolveAddr(transportAddr) + self.timeout = timeout + self.retries = retries + self.tagList = tagList + self.iface = None + + def __repr__(self): + return '%s(%r, timeout=%r, retries=%r, tagList=%r)' % ( + self.__class__.__name__, self.transportAddr, + self.timeout, self.retries, self.tagList + ) + + def getTransportInfo(self): + return self.transportDomain, self.transportAddr + + def setLocalAddress(self, iface): + self.iface = iface + return self + + def openClientMode(self): + self.transport = self.protoTransport().openClientMode(self.iface) + return self.transport + + def verifyDispatcherCompatibility(self, snmpEngine): + if not self.protoTransport.isCompatibleWithDispatcher(snmpEngine.transportDispatcher): + raise error.PySnmpError('Transport %r is not compatible with dispatcher %r' % (self.protoTransport, snmpEngine.transportDispatcher)) + + def _resolveAddr(self, transportAddr): raise NotImplementedError() diff --git a/pysnmp/hlapi/twisted/__init__.py b/pysnmp/hlapi/twisted/__init__.py new file mode 100644 index 0000000..4e3e129 --- /dev/null +++ b/pysnmp/hlapi/twisted/__init__.py @@ -0,0 +1,8 @@ +from pysnmp.proto.rfc1902 import * +from pysnmp.smi.rfc1902 import * +from pysnmp.entity.engine import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.twisted.transport import * +from pysnmp.hlapi.twisted.cmdgen import * +from pysnmp.hlapi.twisted.ntforg import * diff --git a/pysnmp/hlapi/twisted/cmdgen.py b/pysnmp/hlapi/twisted/cmdgen.py new file mode 100644 index 0000000..7f58175 --- /dev/null +++ b/pysnmp/hlapi/twisted/cmdgen.py @@ -0,0 +1,502 @@ +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.twisted.transport import * +from pysnmp.entity.rfc3413 import cmdgen +from pysnmp.error import PySnmpError +from twisted.internet.defer import Deferred +from twisted.python.failure import Failure + +__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib'] + +vbProcessor = CommandGeneratorVarBinds() +lcd = CommandGeneratorLcdConfigurator() + +isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1] + +def getCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Performs SNMP GET query. + + Based on passed parameters, prepares SNMP GET packet + (:RFC:`1905#section-4.2.1`) and schedules its transmission by + :mod:`twisted` I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :class:`~pysnmp.hlapi.CommunityData` or :class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Returns + ------- + deferred : :class:`~twisted.internet.defer.Deferred` + Twisted Deferred object representing work-in-progress. User + is expected to attach his own `success` and `error` callback + functions to the Deferred object though + :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + User `success` callback is called with the following tuple as + its first argument: + + * errorStatus (str) : True value indicates SNMP PDU error. + * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple) : A sequence of + :class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing + MIB variables returned in SNMP response. + + User `error` callback is called with `errorIndication` object wrapped + in :class:`~twisted.python.failure.Failure` object. + + Examples + -------- + >>> from twisted.internet.task import react + >>> from pysnmp.hlapi.twisted import * + >>> + >>> def success((errorStatus, errorIndex, varBinds)): + ... print(errorStatus, errorIndex, varBind) + ... + >>> def failure(errorIndication): + ... print(errorIndication) + ... + >>> def run(reactor): + ... d = getCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))) + ... d.addCallback(success).addErrback(failure) + ... return d + ... + >>> react(run) + (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'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: + deferred.errback(Failure(errorIndication)) + else: + deferred.callback( + (errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + deferred = Deferred() + + cmdgen.GetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), deferred) + ) + return deferred + +def setCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Performs SNMP SET query. + + Based on passed parameters, prepares SNMP SET packet + (:RFC:`1905#section-4.2.5`) and schedules its transmission by + :mod:`twisted` I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :class:`~pysnmp.hlapi.CommunityData` or :class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Returns + ------- + deferred : :class:`~twisted.internet.defer.Deferred` + Twisted Deferred object representing work-in-progress. User + is expected to attach his own `success` and `error` callback + functions to the Deferred object though + :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + User `success` callback is called with the following tuple as + its first argument: + + * errorStatus (str) : True value indicates SNMP PDU error. + * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple) : A sequence of + :class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing + MIB variables returned in SNMP response. + + User `error` callback is called with `errorIndication` object wrapped + in :class:`~twisted.python.failure.Failure` object. + + Examples + -------- + >>> from twisted.internet.task import react + >>> from pysnmp.hlapi.twisted import * + >>> + >>> def success((errorStatus, errorIndex, varBinds)): + ... print(errorStatus, errorIndex, varBind) + ... + >>> def failure(errorIndication): + ... print(errorIndication) + ... + >>> def run(reactor): + ... d = setCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') + ... d.addCallback(success).addErrback(failure) + ... return d + ... + >>> react(run) + (0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('Linux i386'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: + deferred.errback(Failure(errorIndication)) + else: + deferred.callback( + (errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + deferred = Deferred() + + cmdgen.SetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), deferred) + ) + return deferred + +def nextCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Performs SNMP GETNEXT query. + + Based on passed parameters, prepares SNMP GETNEXT packet + (:RFC:`1905#section-4.2.2`) and schedules its transmission by + :mod:`twisted` I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :class:`~pysnmp.hlapi.CommunityData` or :class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Returns + ------- + deferred : :class:`~twisted.internet.defer.Deferred` + Twisted Deferred object representing work-in-progress. User + is expected to attach his own `success` and `error` callback + functions to the Deferred object though + :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + User `success` callback is called with the following tuple as + its first argument: + + * errorStatus (str) : True value indicates SNMP PDU error. + * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple) : + A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Response to GETNEXT always contain + a single row. + + User `error` callback is called with `errorIndication` object wrapped + in :class:`~twisted.python.failure.Failure` object. + + Examples + -------- + >>> from twisted.internet.task import react + >>> from pysnmp.hlapi.twisted import * + >>> + >>> def success((errorStatus, errorIndex, varBindTable)): + ... print(errorStatus, errorIndex, varBindTable) + ... + >>> def failure(errorIndication): + ... print(errorIndication) + ... + >>> def run(reactor): + ... d = nextCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')) + ... d.addCallback(success).addErrback(failure) + ... return d + ... + >>> react(run) + (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'))]]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: + deferred.errback(Failure(errorIndication)) + else: + deferred.callback( + (errorStatus, errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ]) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + deferred = Deferred() + + cmdgen.NextCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), deferred) + ) + return deferred + +def bulkCmd(snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, *varBinds, **options): + """Performs SNMP GETBULK query. + + Based on passed parameters, prepares SNMP GETNEXT packet + (:RFC:`1905#section-4.2.3`) and schedules its transmission by + :mod:`twisted` I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :class:`~pysnmp.hlapi.CommunityData` or :class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + nonRepeaters : int + One MIB variable is requested in response for the first + `nonRepeaters` MIB variables in request. + + maxRepetitions : int + `maxRepetitions` MIB variables are requested in response for each + of the remaining MIB variables in the request (e.g. excluding + `nonRepeaters`). Remote SNMP engine may choose lesser value than + requested. + + \*varBinds : :class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Returns + ------- + deferred : :class:`~twisted.internet.defer.Deferred` + Twisted Deferred object representing work-in-progress. User + is expected to attach his own `success` and `error` callback + functions to the Deferred object though + :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + User `success` callback is called with the following tuple as + its first argument: + + * errorStatus (str) : True value indicates SNMP PDU error. + * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple) : + A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Number of rows might be less or equal + to `maxRepetitions` value in request. + + User `error` callback is called with `errorIndication` object wrapped + in :class:`~twisted.python.failure.Failure` object. + + Examples + -------- + >>> from twisted.internet.task import react + >>> from pysnmp.hlapi.twisted import * + >>> + >>> def success((errorStatus, errorIndex, varBindTable)): + ... print(errorStatus, errorIndex, varBindTable) + ... + >>> def failure(errorIndication): + ... print(errorIndication) + ... + >>> def run(reactor): + ... d = bulkCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... 0, 2, + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')) + ... d.addCallback(success).addErrback(failure) + ... return d + ... + >>> react(run) + (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')), ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1')]]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: + deferred.errback(Failure(errorIndication)) + else: + deferred.callback( + (errorStatus, errorIndex, + [ vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ]) + ) + + addrName, paramsName = lcd.configure( + snmpEngine, authData, transportTarget + ) + + deferred = Deferred() + + cmdgen.BulkCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + nonRepeaters, + maxRepetitions, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), deferred) + ) + return deferred diff --git a/pysnmp/hlapi/twisted/ntforg.py b/pysnmp/hlapi/twisted/ntforg.py new file mode 100644 index 0000000..ac92845 --- /dev/null +++ b/pysnmp/hlapi/twisted/ntforg.py @@ -0,0 +1,147 @@ +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.twisted.transport import * +from pysnmp.entity.rfc3413 import ntforg, context +from twisted.internet import reactor +from twisted.internet.defer import Deferred +from twisted.python.failure import Failure + +__all__ = ['sendNotification'] + +vbProcessor = NotificationOriginatorVarBinds() +lcd = NotificationOriginatorLcdConfigurator() + +def sendNotification(snmpEngine, authData, transportTarget, contextData, + notifyType, varBinds, **options): + """Sends SNMP notification. + + Based on passed parameters, prepares SNMP TRAP or INFORM message + (:RFC:`1905#section-4.2.6`) and schedules its transmission by + :mod:`twisted` I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.hlapi.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + notifyType : str + Indicates type of notification to be sent. Recognized literal + values are *trap* or *inform*. + + varBinds: tuple + Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance + representing a minimum sequence of MIB variables required for + particular notification type. + Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` + objects could be passed instead. In the latter case it is up to + the user to ensure proper Notification PDU contents. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Returns + ------- + deferred : :class:`~twisted.internet.defer.Deferred` + Twisted Deferred object representing work-in-progress. User + is expected to attach his own `success` and `error` callback + functions to the Deferred object though + :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + User `success` callback is called with the following tuple as + its first argument: + + * errorStatus (str) : True value indicates SNMP PDU error. + * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple) : A sequence of + :class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing + MIB variables returned in SNMP response. + + User `error` callback is called with `errorIndication` object wrapped + in :class:`~twisted.python.failure.Failure` object. + + Examples + -------- + >>> from twisted.internet.task import react + >>> from pysnmp.hlapi.twisted import * + >>> + >>> def success((errorStatus, errorIndex, varBinds)): + ... print(errorStatus, errorIndex, varBind) + ... + >>> def failure(errorIndication): + ... print(errorIndication) + ... + >>> def run(reactor): + ... d = sendNotification(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 162)), + ... ContextData(), + ... 'trap', + ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) + ... d.addCallback(success).addErrback(failure) + ... return d + ... + >>> react(run) + (0, 0, []) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, future = cbCtx + if errorIndication: + deferred.errback(Failure(errorIndication)) + else: + deferred.callback( + (errorStatus, errorIndex, + vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)) + ) + + notifyName = lcd.configure( + snmpEngine, authData, transportTarget, notifyType + ) + + def __trapFun(deferred): + deferred.callback((0, 0, [])) + + deferred = Deferred() + + ntforg.NotificationOriginator().sendVarBinds( + snmpEngine, + notifyName, + contextData.contextEngineId, + contextData.contextName, + vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (options.get('lookupMib', True), deferred) + ) + + if notifyType == 'trap': + reactor.callLater(0, __trapFun, deferred) + + return deferred diff --git a/pysnmp/hlapi/twisted/transport.py b/pysnmp/hlapi/twisted/transport.py new file mode 100644 index 0000000..3fcff42 --- /dev/null +++ b/pysnmp/hlapi/twisted/transport.py @@ -0,0 +1,51 @@ +import socket, sys +from pysnmp.carrier.twisted.dgram import udp +from pysnmp.hlapi.transport import AbstractTransportTarget + +__all__ = ['UdpTransportTarget'] + +class UdpTransportTarget(AbstractTransportTarget): + """Creates UDP/IPv4 configuration entry and initialize socket API if needed. + + This object can be used for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine` + class instance. + + See :RFC:`1906#section-3` for more information on the UDP transport mapping. + + Parameters + ---------- + transportAddr : tuple + Indicates remote address in Python :py:mod:`socket` module format + which is a tuple of FQDN, port where FQDN is a string representing + either hostname or IPv4 address in quad-dotted form, port is an + integer. + timeout : int + Response timeout in seconds. + retries : int + Maximum number of request retries, 0 retries means just a single + request. + tagList : str + Arbitrary string that contains a list of tag values which are used + to select target addresses for a particular operation + (:RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.hlapi.twisted import UdpTransportTarget + >>> UdpTransportTarget(('demo.snmplabs.com', 161)) + UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='') + >>> + + """ + transportDomain = udp.domainName + protoTransport = udp.UdpTwistedTransport + def _resolveAddr(self, transportAddr): + try: + return socket.getaddrinfo(transportAddr[0], + transportAddr[1], + socket.AF_INET, + socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror: + raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) |