summaryrefslogtreecommitdiff
path: root/pysnmp
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-02-22 06:43:56 +0100
committerGitHub <noreply@github.com>2019-02-22 06:43:56 +0100
commit74fcc27b038da72c6aa9e2c08b4dac63175b8b5f (patch)
tree0c16c866ba88bf594b2ddea1f54fffe010b66ea8 /pysnmp
parent0cf85fdffc601477afb4a9c5568653154fb4eb32 (diff)
downloadpysnmp-git-74fcc27b038da72c6aa9e2c08b4dac63175b8b5f.tar.gz
Introduce asyncio binding to hlapi.v1arch (#244)
The hlapi.v1arch asyncio API is intended to be very similar to hlapi.v3arch.asyncio from its signature viewpoint, however it should be faster at the expense of no SNMPv3 support.
Diffstat (limited to 'pysnmp')
-rw-r--r--pysnmp/hlapi/v1arch/asyncio/__init__.py13
-rw-r--r--pysnmp/hlapi/v1arch/asyncio/cmdgen.py567
-rw-r--r--pysnmp/hlapi/v1arch/asyncio/dispatch.py29
-rw-r--r--pysnmp/hlapi/v1arch/asyncio/ntforg.py199
-rw-r--r--pysnmp/hlapi/v1arch/asyncio/transport.py126
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/transport.py1
-rw-r--r--pysnmp/hlapi/v3arch/asyncio/transport.py33
7 files changed, 951 insertions, 17 deletions
diff --git a/pysnmp/hlapi/v1arch/asyncio/__init__.py b/pysnmp/hlapi/v1arch/asyncio/__init__.py
new file mode 100644
index 00000000..efebeeb4
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncio/__init__.py
@@ -0,0 +1,13 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncio.transport import *
+from pysnmp.hlapi.v1arch.asyncio.cmdgen import *
+from pysnmp.hlapi.v1arch.asyncio.ntforg import *
+from pysnmp.hlapi.v1arch.asyncio.dispatch import *
+from pysnmp.proto.rfc1902 import *
+from pysnmp.smi.rfc1902 import *
diff --git a/pysnmp/hlapi/v1arch/asyncio/cmdgen.py b/pysnmp/hlapi/v1arch/asyncio/cmdgen.py
new file mode 100644
index 00000000..346b7c76
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncio/cmdgen.py
@@ -0,0 +1,567 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.varbinds import *
+from pysnmp.hlapi.v1arch.asyncio.transport import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.proto import api
+
+try:
+ import asyncio
+
+except ImportError:
+ import trollius as asyncio
+
+__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib']
+
+VB_PROCESSOR = CommandGeneratorVarBinds()
+
+isEndOfMib = lambda varBinds: not api.v2c.apiPDU.getNextVarBinds(varBinds)[1]
+
+
+@asyncio.coroutine
+def getCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Creates a generator to perform SNMP GET query.
+
+ When iterator gets advanced by :py:mod:`asyncio` main loop,
+ SNMP GET request is sent (:RFC:`1905#section-4.2.1`).
+ The iterator yields :py:class:`asyncio.Future` which gets done whenever
+ response arrives or error occurs.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asynio-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`,
+ unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` is present
+ among `varBinds` in which case `lookupMib` gets automatically
+ enabled.
+
+ 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 OID-value pairs in form of base SNMP types (if
+ `lookupMib` is `False`) or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ class instances (if `lookupMib` is `True`) 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.v1arch.asyncio import *
+ >>>
+ >>> @asyncio.coroutine
+ ... def run():
+ ... errorIndication, errorStatus, errorIndex, varBinds = yield from getCmd(
+ ... SnmpDispatcher(),
+ ... CommunityData('public'),
+ ... UdpTransportTarget(('demo.snmplabs.com', 161)),
+ ... 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(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if future.cancelled():
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiPDU.getVarBinds(rspPdu)
+
+ if lookupMib:
+ try:
+ varBinds = VB_PROCESSOR.unmakeVarBinds(
+ snmpDispatcher.cache, varBinds, lookupMib)
+
+ except Exception as e:
+ future.set_exception(e)
+ return
+
+ future.set_result(
+ (errorIndication, errorStatus, errorIndex, varBinds)
+ )
+
+ lookupMib = options.get('lookupMib')
+
+ if not lookupMib and any(isinstance(x, ObjectType) for x in varBinds):
+ lookupMib = True
+
+ if lookupMib:
+ varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.PROTOCOL_MODULES[authData.mpModel]
+
+ reqPdu = pMod.GetRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ future = asyncio.Future()
+
+ snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ return future
+
+
+@asyncio.coroutine
+def setCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Creates a generator to perform SNMP SET query.
+
+ When iterator gets advanced by :py:mod:`asyncio` main loop,
+ SNMP SET request is sent (:RFC:`1905#section-4.2.5`).
+ The iterator yields :py:class:`asyncio.Future` which gets done whenever
+ response arrives or error occurs.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asynio-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`,
+ unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` is present
+ among `varBinds` in which case `lookupMib` gets automatically
+ enabled.
+
+ 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 OID-value pairs in form of base SNMP types (if
+ `lookupMib` is `False`) or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ class instances (if `lookupMib` is `True`) 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.v1arch.asyncio import *
+ >>>
+ >>> @asyncio.coroutine
+ ... def run():
+ ... errorIndication, errorStatus, errorIndex, varBinds = yield from setCmd(
+ ... SnmpDispatcher(),
+ ... CommunityData('public'),
+ ... UdpTransportTarget(('demo.snmplabs.com', 161)),
+ ... 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(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if future.cancelled():
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiPDU.getVarBinds(rspPdu)
+
+ if lookupMib:
+ try:
+ varBinds = VB_PROCESSOR.unmakeVarBinds(
+ snmpDispatcher.cache, varBinds, lookupMib)
+
+ except Exception as e:
+ future.set_exception(e)
+ return
+
+ future.set_result(
+ (errorIndication, errorStatus, errorIndex, varBinds)
+ )
+
+ lookupMib = options.get('lookupMib')
+
+ if not lookupMib and any(isinstance(x, ObjectType) for x in varBinds):
+ lookupMib = True
+
+ if lookupMib:
+ varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.PROTOCOL_MODULES[authData.mpModel]
+
+ reqPdu = pMod.SetRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ future = asyncio.Future()
+
+ snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ return future
+
+
+@asyncio.coroutine
+def nextCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Creates a generator to perform SNMP GETNEXT query.
+
+ When iterator 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
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asynio-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+ Other Parameters
+ ----------------
+ \*\*options:
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`,
+ unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` is present
+ among `varBinds` in which case `lookupMib` gets automatically
+ enabled.
+
+ 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 OID-value pairs in form
+ of base SNMP types (if `lookupMib` is `False`) or
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances (if
+ `lookupMib` is `True`) 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(
+ ... SnmpDispatcher(),
+ ... 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(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if future.cancelled():
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBindTable = pMod.apiPDU.getVarBindTable(reqPdu, rspPdu)
+
+ if lookupMib:
+ try:
+ varBindTable = [
+ VB_PROCESSOR.unmakeVarBinds(snmpDispatcher.cache,
+ varBindTableRow, lookupMib)
+ for varBindTableRow in varBindTable
+ ]
+
+ except Exception as e:
+ future.set_exception(e)
+ return
+
+ future.set_result(
+ (errorIndication, errorStatus, errorIndex, varBindTable)
+ )
+
+ lookupMib = options.get('lookupMib')
+
+ if not lookupMib and any(isinstance(x, ObjectType) for x in varBinds):
+ lookupMib = True
+
+ if lookupMib:
+ varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.PROTOCOL_MODULES[authData.mpModel]
+
+ reqPdu = pMod.GetNextRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ future = asyncio.Future()
+
+ snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ return future
+
+
+@asyncio.coroutine
+def bulkCmd(snmpDispatcher, authData, transportTarget,
+ nonRepeaters, maxRepetitions, *varBinds, **options):
+ """Creates a generator to perform SNMP GETBULK query.
+
+ When iterator 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
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asynio-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ 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:`tuple` of OID-value pairs or :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 `False`,
+ unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` is present
+ among `varBinds` in which case `lookupMib` gets automatically
+ enabled.
+
+ 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]`
+ varBindTable: tuple
+ A sequence of sequences (e.g. 2-D array) of OID-value pairs in form
+ of base SNMP types (if `lookupMib` is `False`) or
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances (if
+ `lookupMib` is `True`) a table of MIB variables returned in SNMP
+ response, with up to `maxRepetitions` rows, i.e.
+ `len(varBindTable) <= maxRepetitions`.
+
+ For `0 <= i < len(varBindTable)` and `0 <= j < len(varBinds)`,
+ `varBindTable[i][j]` represents:
+
+ - For non-repeaters (`j < nonRepeaters`), the first lexicographic
+ successor of `varBinds[j]`, regardless the value of `i`, or an
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` instance with the
+ :py:obj:`~pysnmp.proto.rfc1905.endOfMibView` value if no such
+ successor exists;
+ - For repeaters (`j >= nonRepeaters`), the `i`-th lexicographic
+ successor of `varBinds[j]`, or an
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` instance with the
+ :py:obj:`~pysnmp.proto.rfc1905.endOfMibView` value if no such
+ successor exists.
+
+ See :rfc:`3416#section-4.2.3` for details on the underlying
+ `GetBulkRequest-PDU` and the associated `GetResponse-PDU`, such as
+ specific conditions under which the server may truncate the response,
+ causing `varBindTable` to have less than `maxRepetitions` rows.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> import asyncio
+ >>> from pysnmp.hlapi.v1arch.asyncio import *
+ >>>
+ >>> @asyncio.coroutine
+ ... def run():
+ ... errorIndication, errorStatus, errorIndex, varBinds = yield from bulkCmd(
+ ... SnmpDispatcher(),
+ ... CommunityData('public'),
+ ... UdpTransportTarget(('demo.snmplabs.com', 161)),
+ ... 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(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if future.cancelled():
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBindTable = pMod.apiBulkPDU.getVarBindTable(reqPdu, rspPdu)
+
+ if lookupMib:
+ try:
+ varBindTable = [
+ VB_PROCESSOR.unmakeVarBinds(snmpDispatcher.cache,
+ varBindTableRow, lookupMib)
+ for varBindTableRow in varBindTable
+ ]
+
+ except Exception as e:
+ future.set_exception(e)
+ return
+
+ future.set_result(
+ (errorIndication, errorStatus, errorIndex, varBindTable)
+ )
+
+ lookupMib = options.get('lookupMib')
+
+ if not lookupMib and any(isinstance(x, ObjectType) for x in varBinds):
+ lookupMib = True
+
+ if lookupMib:
+ varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.PROTOCOL_MODULES[authData.mpModel]
+
+ reqPdu = pMod.GetBulkRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiBulkPDU.setNonRepeaters(reqPdu, nonRepeaters)
+ pMod.apiBulkPDU.setMaxRepetitions(reqPdu, maxRepetitions)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ future = asyncio.Future()
+
+ snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ return future
diff --git a/pysnmp/hlapi/v1arch/asyncio/dispatch.py b/pysnmp/hlapi/v1arch/asyncio/dispatch.py
new file mode 100644
index 00000000..d908beb9
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncio/dispatch.py
@@ -0,0 +1,29 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.carrier.asyncio.dispatch import AsyncioDispatcher
+from pysnmp.hlapi.v1arch.dispatch import AbstractSnmpDispatcher
+
+__all__ = ['SnmpDispatcher']
+
+
+class SnmpDispatcher(AbstractSnmpDispatcher):
+ """Creates SNMP message dispatcher object.
+
+ `SnmpDispatcher` object manages send and receives SNMP PDU
+ messages through underlying transport dispatcher and dispatches
+ them to the callers.
+
+ `SnmpDispatcher` is the only stateful object, all `hlapi.v1arch` SNMP
+ operations require an instance of `SnmpDispatcher`. Users do not normally
+ request services directly from `SnmpDispather`, but pass it around to
+ other `hlapi.v1arch` interfaces.
+
+ It is possible to run multiple instances of `SnmpDispatcher` in the
+ application. In a multithreaded environment, each thread that
+ works with SNMP must have its own `SnmpDispatcher` instance.
+ """
+ PROTO_DISPATCHER = AsyncioDispatcher
diff --git a/pysnmp/hlapi/v1arch/asyncio/ntforg.py b/pysnmp/hlapi/v1arch/asyncio/ntforg.py
new file mode 100644
index 00000000..25d831e9
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncio/ntforg.py
@@ -0,0 +1,199 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.varbinds import *
+from pysnmp.hlapi.v1arch.asyncio.transport import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.proto import api
+
+try:
+ import asyncio
+
+except ImportError:
+ import trollius as asyncio
+
+__all__ = ['sendNotification']
+
+VB_PROCESSOR = NotificationOriginatorVarBinds()
+
+
+@asyncio.coroutine
+def sendNotification(snmpDispatcher, authData, transportTarget,
+ notifyType, *varBinds, **options):
+ """Creates a generator to send SNMP notification.
+
+ When iterator 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
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asynio-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ notifyType : str
+ Indicates type of notification to be sent. Recognized literal
+ values are *trap* or *inform*.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU places rigid requirement on the ordering of
+ the variable-bindings.
+
+ Mandatory variable-bindings:
+
+ 0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ 1. SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Optional variable-bindings (applicable to SNMP v1 TRAP):
+
+ 2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ 3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ 4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ Informational variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`,
+ unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` or
+ :py:class:`~pysnmp.smi.rfc1902.NotificationType` is present
+ among `varBinds` in which case `lookupMib` gets automatically
+ enabled.
+
+ 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 OID-value pairs in form of base SNMP types (if
+ `lookupMib` is `False`) or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ class instances (if `lookupMib` is `True`) 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 sendNotification(
+ ... SnmpDispatcher(),
+ ... CommunityData('public'),
+ ... UdpTransportTarget(('demo.snmplabs.com', 162)),
+ ... 'trap',
+ ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown')))
+ ... print(errorIndication, errorStatus, errorIndex, varBinds)
+ ...
+ >>> asyncio.get_event_loop().run_until_complete(run())
+ (None, 0, 0, [])
+ >>>
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if future.cancelled():
+ return
+
+ errorStatus = pMod.apiTrapPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiTrapPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiTrapPDU.getVarBinds(rspPdu)
+
+ try:
+ varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(snmpDispatcher.cache, varBinds,
+ lookupMib)
+ except Exception as e:
+ future.set_exception(e)
+
+ else:
+ future.set_result(
+ (errorIndication, errorStatus, errorIndex, varBindsUnmade)
+ )
+
+ lookupMib = options.get('lookupMib')
+
+ if not lookupMib and any(isinstance(x, (NotificationType, ObjectType))
+ for x in varBinds):
+ lookupMib = True
+
+ if lookupMib:
+ varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ # # make sure required PDU payload is in place
+ # completeVarBinds = []
+ #
+ # # ensure sysUpTime
+ # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+ #
+ # # ensure sysUpTime
+ # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+ #
+ # # ensure snmpTrapOID
+ # if len(varBinds) < 2 or varBinds[1][0] != pMod.apiTrapPDU.snmpTrapOID:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+
+ # input PDU is always v2c
+ pMod = api.PROTOCOL_MODULES[api.SNMP_VERSION_2C]
+
+ if notifyType == 'trap':
+ reqPdu = pMod.TrapPDU()
+ else:
+ reqPdu = pMod.InformRequestPDU()
+
+ pMod.apiTrapPDU.setDefaults(reqPdu)
+ pMod.apiTrapPDU.setVarBinds(reqPdu, varBinds)
+
+ if authData.mpModel == 0:
+ reqPdu = rfc2576.v2ToV1(reqPdu)
+
+ future = asyncio.Future()
+
+ snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ 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/v1arch/asyncio/transport.py b/pysnmp/hlapi/v1arch/asyncio/transport.py
new file mode 100644
index 00000000..5d4895e5
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncio/transport.py
@@ -0,0 +1,126 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+import socket
+import sys
+
+from pysnmp.carrier.asyncio.dgram import udp
+from pysnmp.carrier.asyncio.dgram import udp6
+from pysnmp.error import PySnmpError
+from pysnmp.hlapi.transport import AbstractTransportTarget
+
+__all__ = ['Udp6TransportTarget', 'UdpTransportTarget']
+
+
+class UdpTransportTarget(AbstractTransportTarget):
+ """Represent UDP/IPv4 transport endpoint.
+
+ This object can be used for passing UDP/IPv4 configuration
+ information to the
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.AsyncCommandGenerator` and
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.AsyncNotificationOriginator`
+ objects scheduled on I/O by :py:class:`~pysnmp.hlapi.SnmpDispatcher`
+ 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: :py:class:`int`
+ Response timeout in seconds.
+ retries: :py:class:`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.v1arch.asyncore import UdpTransportTarget
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161))
+ UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5)
+ >>>
+ """
+ TRANSPORT_DOMAIN = udp.domainName
+ PROTO_TRANSPORT = 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 as exc:
+ raise PySnmpError('Bad IPv4/UDP transport address %s: %s' % (
+ '@'.join([str(x) for x in transportAddr]), exc))
+
+
+class Udp6TransportTarget(AbstractTransportTarget):
+ """Represent UDP/IPv6 transport endpoint.
+
+ This object can be used for passing UDP/IPv6 configuration
+ information to the
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.AsyncCommandGenerator` and
+ :py:class:`~pysnmp.hlapi.v1arch.asyncio.AsyncNotificationOriginator`
+ objects scheduled on I/O by :py:class:`~pysnmp.hlapi.SnmpDispatcher`
+ 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='')
+ >>>
+ """
+ TRANSPORT_DOMAIN = udp6.domainName
+ PROTO_TRANSPORT = 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 as exc:
+ raise PySnmpError('Bad IPv6/UDP transport address %s: %s' % (
+ '@'.join([str(x) for x in transportAddr]), exc))
diff --git a/pysnmp/hlapi/v1arch/asyncore/transport.py b/pysnmp/hlapi/v1arch/asyncore/transport.py
index 507424fe..ad180337 100644
--- a/pysnmp/hlapi/v1arch/asyncore/transport.py
+++ b/pysnmp/hlapi/v1arch/asyncore/transport.py
@@ -42,7 +42,6 @@ class UdpTransportTarget(AbstractTransportTarget):
>>> UdpTransportTarget(('demo.snmplabs.com', 161))
UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5)
>>>
-
"""
TRANSPORT_DOMAIN = udp.DOMAIN_NAME
PROTO_TRANSPORT = udp.UdpSocketTransport
diff --git a/pysnmp/hlapi/v3arch/asyncio/transport.py b/pysnmp/hlapi/v3arch/asyncio/transport.py
index 9079c1c8..0b795163 100644
--- a/pysnmp/hlapi/v3arch/asyncio/transport.py
+++ b/pysnmp/hlapi/v3arch/asyncio/transport.py
@@ -16,27 +16,30 @@ __all__ = ['Udp6TransportTarget', 'UdpTransportTarget']
class UdpTransportTarget(AbstractTransportTarget):
- """Creates UDP/IPv4 configuration entry and initialize socket API if needed.
+ """Represent UDP/IPv6 transport endpoint.
- This object can be used for adding new entries to Local Configuration
- Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.SnmpEngine`
+ This object can be used for passing UDP/IPv6 configuration
+ information to the
+ :py:class:`~pysnmp.hlapi.v3arch.asyncio.AsyncCommandGenerator` and
+ :py:class:`~pysnmp.hlapi.v3arch.asyncio.AsyncNotificationOriginator`
+ Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.v3arch.SnmpEngine`
class instance.
See :RFC:`1906#section-3` for more information on the UDP transport mapping.
Parameters
----------
- transportAddr : tuple
+ 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
+ timeout: int
Response timeout in seconds.
- retries : int
+ retries: int
Maximum number of request retries, 0 retries means just a single
request.
- tagList : str
+ 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`).
@@ -47,7 +50,6 @@ class UdpTransportTarget(AbstractTransportTarget):
>>> UdpTransportTarget(('demo.snmplabs.com', 161))
UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='')
>>>
-
"""
TRANSPORT_DOMAIN = udp.domainName
PROTO_TRANSPORT = udp.UdpAsyncioTransport
@@ -68,10 +70,10 @@ 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`
+ :py:class:`~pysnmp.hlapi.v3arch.asyncio.AsyncCommandGenerator` or
+ :py:class:`~pysnmp.hlapi.v3arch.asyncio.AsyncNotificationOriginator`
+ and their derivatives for adding new entries to Local Configuration
+ Datastore (LCD) managed by :py:class:`~pysnmp.hlapi.v3arch.SnmpEngine`
class instance.
See :RFC:`1906#section-3`, :RFC:`2851#section-4` for more information
@@ -84,12 +86,12 @@ class Udp6TransportTarget(AbstractTransportTarget):
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
+ timeout: int
Response timeout in seconds.
- retries : int
+ retries: int
Maximum number of request retries, 0 retries means just a single
request.
- tagList : str
+ 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`).
@@ -108,7 +110,6 @@ class Udp6TransportTarget(AbstractTransportTarget):
>>> Udp6TransportTarget(('::', 161))
Udp6TransportTarget(('::', 161), timeout=1, retries=5, tagList='')
>>>
-
"""
TRANSPORT_DOMAIN = udp6.domainName
PROTO_TRANSPORT = udp6.Udp6AsyncioTransport