summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2014-11-16 16:14:37 +0000
committerelie <elie>2014-11-16 16:14:37 +0000
commitedff85c75a5ba51c6824f6d09ec55986682db335 (patch)
treec0216f83de60b93ef9c24ad801a47e2a14308b6e
parent481200dc56925509a54b89c28d054ba28f4e437c (diff)
downloadpysnmp-edff85c75a5ba51c6824f6d09ec55986682db335.tar.gz
asyncio-backed SNMP Applications APIs redesigned for better usability in
form of coroutines
-rw-r--r--examples/v3arch/asyncio/agent/ntforg/inform-v3.py71
-rw-r--r--examples/v3arch/asyncio/agent/ntforg/trap-v1.py120
-rw-r--r--examples/v3arch/asyncio/manager/cmdgen/get-v2c-custom-timeout.py40
-rw-r--r--examples/v3arch/asyncio/manager/cmdgen/getbulk-v2c.py87
-rw-r--r--examples/v3arch/asyncio/manager/cmdgen/getnext-v2c-from-specific-address.py82
-rw-r--r--pysnmp/entity/rfc3413/asyncio/cmdgen.py105
-rw-r--r--pysnmp/entity/rfc3413/asyncio/ntforg.py1
7 files changed, 217 insertions, 289 deletions
diff --git a/examples/v3arch/asyncio/agent/ntforg/inform-v3.py b/examples/v3arch/asyncio/agent/ntforg/inform-v3.py
index f74018d..1fa3de7 100644
--- a/examples/v3arch/asyncio/agent/ntforg/inform-v3.py
+++ b/examples/v3arch/asyncio/agent/ntforg/inform-v3.py
@@ -65,18 +65,26 @@ config.addNotificationTarget(
config.addContext(snmpEngine, '')
config.addVacmUser(snmpEngine, 3, 'usr-md5-none', 'authNoPriv', (), (), (1,3,6))
-# Create Notification Originator App instance.
-ntfOrg = ntforg.NotificationOriginator()
-
- # Create default SNMP context where contextEngineId == SnmpEngineId
-snmpContext = context.SnmpContext(snmpEngine)
+@asyncio.coroutine
+def snmpOperation(snmpEngine, target, snmpContext, contextName,
+ notificationName, instanceIndex, additionalVarBinds):
+ ( snmpEngine,
+ errorIndication,
+ errorStatus,
+ errorIndex,
+ varBinds ) = yield from ntforg.NotificationOriginator().sendVarBinds(
+ snmpEngine,
+ target,
+ snmpContext,
+ contextName,
+ notificationName,
+ instanceIndex,
+ additionalVarBinds
+ )
-# Error/confirmation receiver
-def cbFun(future):
- snmpEngine, errorIndication, errorStatus, errorIndex, varBinds = future.result()
print('Notification status - %s' % (
- errorIndication and errorIndication or 'delivered'
- )
+ errorIndication and errorIndication or 'delivered'
+ )
)
# This also terminates internal timer
@@ -85,33 +93,24 @@ def cbFun(future):
udp.domainName
)
- # Finish all scheduled tasks and end the loop
- loop.stop()
-
-# Build and submit notification message to dispatcher
-future = ntfOrg.sendVarBinds(
- snmpEngine,
- # Notification targets
- 'my-notification',
- # SNMP Context
- snmpContext,
- # contextName
- '',
- # notification name (SNMPv2-MIB::coldStart)
- (1,3,6,1,6,3,1,1,5,1),
- # notification objects instance index
- None,
- # additional var-binds: ( (oid, value), ... )
- [ ((1,3,6,1,2,1,1,5,0), rfc1902.OctetString('system name')) ]
+# Initiate sending SNMP message
+loop.run_until_complete(
+ snmpOperation(
+ snmpEngine,
+ # Notification targets
+ 'my-notification',
+ # Default SNMP context where contextEngineId == SnmpEngineId
+ context.SnmpContext(snmpEngine),
+ # contextName
+ '',
+ # notification name (SNMPv2-MIB::coldStart)
+ (1,3,6,1,6,3,1,1,5,1),
+ # notification objects instance index
+ None,
+ # additional var-binds: ( (oid, value), ... )
+ [ ((1,3,6,1,2,1,1,5,0), rfc1902.OctetString('system name')) ]
+ )
)
-# Register error/response receiver function on future
-future.add_done_callback(cbFun)
-
-print('Notification is scheduled to be sent')
-
-# Run asyncio main loop
-loop.run_forever()
-
# Clear the event loop
loop.close()
diff --git a/examples/v3arch/asyncio/agent/ntforg/trap-v1.py b/examples/v3arch/asyncio/agent/ntforg/trap-v1.py
index 2dd6f4a..1406e32 100644
--- a/examples/v3arch/asyncio/agent/ntforg/trap-v1.py
+++ b/examples/v3arch/asyncio/agent/ntforg/trap-v1.py
@@ -69,64 +69,74 @@ config.addNotificationTarget(
config.addContext(snmpEngine, '')
config.addVacmUser(snmpEngine, 1, 'my-area', 'noAuthNoPriv', (), (), (1,3,6))
-# Create Notification Originator App instance.
-ntfOrg = ntforg.NotificationOriginator()
-
- # Create default SNMP context where contextEngineId == SnmpEngineId
-snmpContext = context.SnmpContext(snmpEngine)
-
-# Prepare notification to be sent returning asyncio future object
-future = ntfOrg.sendVarBinds(
- snmpEngine,
- # Notification targets
- 'my-notification',
- # SNMP Context
- snmpContext,
- # contextName
- '',
- # notification name: Generic Trap #6 (enterpriseSpecific)
- # and Specific Trap 432
- '1.3.6.1.4.1.20408.4.1.1.2.0.432',
- # notification objects instance index
- None,
- # additional var-binds holding SNMPv1 TRAP details
- [
- # Uptime value with 12345
- (rfc1902.ObjectName('1.3.6.1.2.1.1.3.0'),
- rfc1902.TimeTicks(12345)),
- # Agent Address with '127.0.0.1'
- (rfc1902.ObjectName('1.3.6.1.6.3.18.1.3.0'),
- rfc1902.IpAddress('127.0.0.1')),
- # Enterprise OID with 1.3.6.1.4.1.20408.4.1.1.2
- (rfc1902.ObjectName('1.3.6.1.6.3.1.1.4.3.0'),
- rfc1902.ObjectName('1.3.6.1.4.1.20408.4.1.1.2')),
- # managed object '1.3.6.1.2.1.1.1.0' = 'my system'
- (rfc1902.ObjectName('1.3.6.1.2.1.1.1.0'),
- rfc1902.OctetString('my system'))
- ]
-)
-
-print('Notification is scheduled to be sent')
-
@asyncio.coroutine
-def wait(future):
- # a hack: wait for outgoing packet to leave us
- yield from asyncio.sleep(1)
- future.set_result(True)
-
-asyncio.async(wait(future))
-
-# Run asyncio main loop
-loop.run_until_complete(future)
-
-# This also terminates internal timer
-config.delTransport(
- snmpEngine,
- udp.domainName
+def snmpOperation(snmpEngine, target, snmpContext, contextName,
+ notificationName, instanceIndex, additionalVarBinds):
+ future = ntforg.NotificationOriginator().sendVarBinds(
+ snmpEngine,
+ target,
+ snmpContext,
+ contextName,
+ notificationName,
+ instanceIndex,
+ additionalVarBinds
+ )
+
+ # We know we are sending TRAP which will never produce any response.
+ # Therefore we simulate successful response here.
+ future.set_result((snmpEngine, None, 0, 0, ()))
+
+ ( snmpEngine,
+ errorIndication,
+ errorStatus,
+ errorIndex,
+ varBinds ) = yield from future
+
+ if errorIndication:
+ print(errorIndication)
+
+ # This also terminates internal timer
+ config.delTransport(
+ snmpEngine,
+ udp.domainName
+ )
+
+# Initiate sending SNMP message
+asyncio.async(
+ snmpOperation(
+ snmpEngine,
+ # Notification targets
+ 'my-notification',
+ # Default SNMP context where contextEngineId == SnmpEngineId
+ context.SnmpContext(snmpEngine),
+ # contextName
+ '',
+ # notification name: Generic Trap #6 (enterpriseSpecific)
+ # and Specific Trap 432
+ '1.3.6.1.4.1.20408.4.1.1.2.0.432',
+ # notification objects instance index
+ None,
+ # additional var-binds holding SNMPv1 TRAP details
+ [
+ # Uptime value with 12345
+ (rfc1902.ObjectName('1.3.6.1.2.1.1.3.0'),
+ rfc1902.TimeTicks(12345)),
+ # Agent Address with '127.0.0.1'
+ (rfc1902.ObjectName('1.3.6.1.6.3.18.1.3.0'),
+ rfc1902.IpAddress('127.0.0.1')),
+ # Enterprise OID with 1.3.6.1.4.1.20408.4.1.1.2
+ (rfc1902.ObjectName('1.3.6.1.6.3.1.1.4.3.0'),
+ rfc1902.ObjectName('1.3.6.1.4.1.20408.4.1.1.2')),
+ # managed object '1.3.6.1.2.1.1.1.0' = 'my system'
+ (rfc1902.ObjectName('1.3.6.1.2.1.1.1.0'),
+ rfc1902.OctetString('my system'))
+ ]
+ )
)
-# Finish all scheduled tasks and end the loop
-loop.stop()
+# Since SNMP TRAP's are unacknowledged, there's nothing to wait for. So we
+# simulate other loop activities by sleep()'ing.
+loop.run_until_complete(asyncio.sleep(1))
# Clear the event loop
loop.close()
diff --git a/examples/v3arch/asyncio/manager/cmdgen/get-v2c-custom-timeout.py b/examples/v3arch/asyncio/manager/cmdgen/get-v2c-custom-timeout.py
index 61cefed..990bb83 100644
--- a/examples/v3arch/asyncio/manager/cmdgen/get-v2c-custom-timeout.py
+++ b/examples/v3arch/asyncio/manager/cmdgen/get-v2c-custom-timeout.py
@@ -53,9 +53,20 @@ config.addTargetAddr(
retryCount=5
)
-# Error/response receiver
-def cbFun(future):
- (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds) = future.result()
+@asyncio.coroutine
+def snmpOperation(snmpEngine, target, contextEngineId, contextName, varBinds):
+ ( snmpEngine,
+ errorIndication,
+ errorStatus,
+ errorIndex,
+ varBinds ) = yield from cmdgen.GetCommandGenerator().sendVarBinds(
+ snmpEngine,
+ target,
+ contextEngineId,
+ contextName,
+ varBinds
+ )
+
if errorIndication:
print(errorIndication)
elif errorStatus:
@@ -74,22 +85,13 @@ def cbFun(future):
udp.domainName
)
- # Finish all scheduled tasks and end the loop
- loop.stop()
-
-# Prepare request to be sent, receive an asyncio future object
-future = cmdgen.GetCommandGenerator().sendVarBinds(
- snmpEngine,
- 'my-router',
- None, '', # contextEngineId, contextName
- ( ('1.3.6.1.2.1.1.1.0', None), ),
+loop.run_until_complete(
+ snmpOperation(
+ snmpEngine,
+ 'my-router',
+ None, '', # contextEngineId, contextName
+ ( ('1.3.6.1.2.1.1.1.0', None), )
+ )
)
-# Register error/response receiver function on future
-future.add_done_callback(cbFun)
-
-# Run asyncio main loop
-loop.run_forever()
-
-# Clear the event loop
loop.close()
diff --git a/examples/v3arch/asyncio/manager/cmdgen/getbulk-v2c.py b/examples/v3arch/asyncio/manager/cmdgen/getbulk-v2c.py
index 0b40bd0..54c0972 100644
--- a/examples/v3arch/asyncio/manager/cmdgen/getbulk-v2c.py
+++ b/examples/v3arch/asyncio/manager/cmdgen/getbulk-v2c.py
@@ -53,57 +53,60 @@ config.addTargetAddr(
'my-creds'
)
-# Error/response receiver
-def cbFun(cbCtx):
- (snmpEngine, errorIndication,
- errorStatus, errorIndex, varBindTable, status) = cbCtx.result()
- if errorIndication:
- print(errorIndication)
- elif errorStatus:
- print('%s at %s' % (
- errorStatus.prettyPrint(),
- errorIndex and varBindTable[-1][int(errorIndex)-1][0] or '?'
- )
- )
- else:
- for varBindRow in varBindTable:
- for oid, val in varBindRow:
- print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
-
- # Stop mainloop when we are done walking (optional)
- for oid, val in varBindRow:
- if not val.isSameTypeWith(rfc1905.endOfMibView):
- # Re-create future for next GETNEXT iteration
- future = asyncio.Future()
- future.add_done_callback(cbFun)
+@asyncio.coroutine
+def snmpOperation(snmpEngine, target, contextEngineId, contextName,
+ nonRepeaters, maxRepetitions, varBinds):
+ initialVarBinds = varBinds
+ while varBinds:
+ ( snmpEngine,
+ errorIndication,
+ errorStatus,
+ errorIndex,
+ varBindTable ) = yield from cmdgen.BulkCommandGenerator().sendVarBinds(
+ snmpEngine,
+ target,
+ contextEngineId,
+ contextName,
+ nonRepeaters,
+ maxRepetitions,
+ varBinds
+ )
- # This also indicates that we wish to continue walking
- status['future'] = future
- return
+ if errorIndication:
+ print(errorIndication)
+ break
+ elif errorStatus:
+ print('%s at %s' % (
+ errorStatus.prettyPrint(),
+ errorIndex and varBindTable[-1][int(errorIndex)-1][0] or '?'
+ )
+ )
+ break
+ else:
+ for varBindRow in varBindTable:
+ for oid, val in varBindRow:
+ print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
+ errorIndication, varBinds = cmdgen.getNextVarBinds(
+ initialVarBinds, varBindRow
+ )
+
# This also terminates internal timer
config.delTransport(
snmpEngine,
udp.domainName
)
-
- # Stop mainloop on SNMP error (optional)
+
loop.stop()
-# Prepare request to be sent, receive an asyncio future object
-future = cmdgen.BulkCommandGenerator().sendVarBinds(
- snmpEngine,
- 'my-router',
- None, '', # contextEngineId, contextName
- 0, 25, # non-repeaters, max-repetitions
- ( ('1.3.6.1.2.1.1', None), ('1.3.6.1.4.1.1', None) )
+loop.run_until_complete(
+ snmpOperation(
+ snmpEngine,
+ 'my-router',
+ None, '', # contextEngineId, contextName
+ 0, 25, # nonRepeaters, maxRepetitions
+ ( ('1.3.6.1.2.1.1', None), ('1.3.6.1.2.1.11', None) )
+ )
)
-# Register error/response receiver function on future
-future.add_done_callback(cbFun)
-
-# Run asyncio main loop
-loop.run_forever()
-
-# Clear the event loop
loop.close()
diff --git a/examples/v3arch/asyncio/manager/cmdgen/getnext-v2c-from-specific-address.py b/examples/v3arch/asyncio/manager/cmdgen/getnext-v2c-from-specific-address.py
index 792487c..2f1f293 100644
--- a/examples/v3arch/asyncio/manager/cmdgen/getnext-v2c-from-specific-address.py
+++ b/examples/v3arch/asyncio/manager/cmdgen/getnext-v2c-from-specific-address.py
@@ -53,56 +53,56 @@ config.addTargetAddr(
'my-creds'
)
-# Error/response receiver
-def cbFun(future):
- (snmpEngine, errorIndication,
- errorStatus, errorIndex, varBindTable, status) = future.result()
- if errorIndication:
- print(errorIndication)
- elif errorStatus:
- print('%s at %s' % (
- errorStatus.prettyPrint(),
- errorIndex and varBindTable[-1][int(errorIndex)-1][0] or '?'
- )
- )
- else:
- for varBindRow in varBindTable:
- for oid, val in varBindRow:
- print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
-
- # Stop mainloop when we are done walking (optional)
- for oid, val in varBindRow:
- if not val.isSameTypeWith(rfc1905.endOfMibView):
- # Re-create future for next GETNEXT iteration
- future = asyncio.Future()
- future.add_done_callback(cbFun)
+@asyncio.coroutine
+def snmpOperation(snmpEngine, target, contextEngineId, contextName, varBinds):
+ initialVarBinds = varBinds
+ while varBinds:
+ ( snmpEngine,
+ errorIndication,
+ errorStatus,
+ errorIndex,
+ varBindTable ) = yield from cmdgen.NextCommandGenerator().sendVarBinds(
+ snmpEngine,
+ target,
+ contextEngineId,
+ contextName,
+ varBinds
+ )
- # This also indicates that we wish to continue walking
- status['future'] = future
- return
+ if errorIndication:
+ print(errorIndication)
+ break
+ elif errorStatus:
+ print('%s at %s' % (
+ errorStatus.prettyPrint(),
+ errorIndex and varBindTable[-1][int(errorIndex)-1][0] or '?'
+ )
+ )
+ break
+ else:
+ for varBindRow in varBindTable:
+ for oid, val in varBindRow:
+ print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
+ errorIndication, varBinds = cmdgen.getNextVarBinds(
+ initialVarBinds, varBindRow
+ )
+
# This also terminates internal timer
config.delTransport(
snmpEngine,
udp.domainName
)
-
- # Stop mainloop on SNMP error (optional)
+
loop.stop()
-# Prepare request to be sent, receive an asyncio future object
-future = cmdgen.NextCommandGenerator().sendVarBinds(
- snmpEngine,
- 'my-router',
- None, '', # contextEngineId, contextName
- ( ('1.3.6.1.2.1.1', None), ('1.3.6.1.2.1.11', None) )
+loop.run_until_complete(
+ snmpOperation(
+ snmpEngine,
+ 'my-router',
+ None, '', # contextEngineId, contextName
+ ( ('1.3.6.1.2.1.1', None), ('1.3.6.1.2.1.11', None) )
+ )
)
-# Register error/response receiver function on future
-future.add_done_callback(cbFun)
-
-# Run asyncio main loop
-loop.run_forever()
-
-# Clear the event loop
loop.close()
diff --git a/pysnmp/entity/rfc3413/asyncio/cmdgen.py b/pysnmp/entity/rfc3413/asyncio/cmdgen.py
index 8a127c2..6fcf0f2 100644
--- a/pysnmp/entity/rfc3413/asyncio/cmdgen.py
+++ b/pysnmp/entity/rfc3413/asyncio/cmdgen.py
@@ -2,6 +2,7 @@
# 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:
@@ -34,6 +35,8 @@ except ImportError:
from pysnmp.error import PySnmpError
raise PySnmpError('The asyncio transport is not available')
+getNextVarBinds = cmdgen.getNextVarBinds
+
class AbstractCommandGenerator:
commandGenerator = None
@@ -64,98 +67,14 @@ class GetCommandGenerator(AbstractCommandGenerator):
class SetCommandGenerator(AbstractCommandGenerator):
commandGenerator = cmdgen.SetCommandGenerator()
-class AbstractNextCommandGenerator:
- commandGenerator = None
-
- def _cbFunWithFuture(self, snmpEngine, sendRequestHandle, errorIndication,
- errorStatus, errorIndex, varBinds, cbCtx):
- targetName, contextEngineId, contextName, reqVarBinds, futureCtx = cbCtx
- status = {}
-
- def _nextCbFunClosure():
- def _cbFun(future):
- if not status.get('future'):
- return
- errorIndication, nextVarBinds = cmdgen.getNextVarBinds(
- [ (v2c.ObjectIdentifier(x[0]), x[1]) for x in reqVarBinds ],
- varBinds[-1]
- )
- self.commandGenerator.sendVarBinds(
- snmpEngine,
- targetName,
- contextEngineId,
- contextName,
- nextVarBinds,
- self._cbFunWithFuture,
- (targetName, contextEngineId, contextName, nextVarBinds, { 'future': status['future']})
- )
- return _cbFun
-
- future = futureCtx['future']
- # add our own callback sending request for next vars if needed
- future.add_done_callback(_nextCbFunClosure())
- future.set_result(
- (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds, status)
- )
-
- def sendVarBinds(self, snmpEngine, targetName,
- contextEngineId, contextName, varBinds):
- future = asyncio.Future()
- self.commandGenerator.sendVarBinds(
- snmpEngine,
- targetName,
- contextEngineId,
- contextName,
- varBinds,
- self._cbFunWithFuture,
- (targetName, contextEngineId, contextName, varBinds, { 'future': future })
- )
- return future
-
-class NextCommandGeneratorSingleRun(AbstractNextCommandGenerator):
- commandGenerator = cmdgen.NextCommandGeneratorSingleRun()
-
-class NextCommandGenerator(AbstractNextCommandGenerator):
+class NextCommandGenerator(AbstractCommandGenerator):
commandGenerator = cmdgen.NextCommandGenerator()
-class AbstractBulkCommandGenerator:
- commandGenerator = None
-
- def _cbFunWithFuture(self, snmpEngine, sendRequestHandle, errorIndication,
- errorStatus, errorIndex, varBinds, cbCtx):
- targetName, contextEngineId, contextName, nonRepeaters, maxRepetitions, reqVarBinds, futureCtx = cbCtx
- status = {}
-
- def _nextCbFunClosure():
- def _cbFun(future):
- if not status.get('future'):
- return
- errorIndication, nextVarBinds = cmdgen.getNextVarBinds(
- [ (v2c.ObjectIdentifier(x[0]), x[1]) for x in reqVarBinds ],
- varBinds[-1]
- )
- self.commandGenerator.sendVarBinds(
- snmpEngine,
- targetName,
- contextEngineId,
- contextName,
- nonRepeaters,
- maxRepetitions,
- nextVarBinds,
- self._cbFunWithFuture,
- (targetName, contextEngineId, contextName, nonRepeaters, maxRepetitions, nextVarBinds, { 'future': status['future']})
- )
- return _cbFun
-
- future = futureCtx['future']
- # add our own callback sending request for next vars if needed
- future.add_done_callback(_nextCbFunClosure())
- future.set_result(
- (snmpEngine, errorIndication, errorStatus, errorIndex, varBinds, status)
- )
+class BulkCommandGenerator(AbstractCommandGenerator):
+ commandGenerator = cmdgen.BulkCommandGenerator()
- def sendVarBinds(self, snmpEngine, targetName,
- contextEngineId, contextName,
+ def sendVarBinds(self, snmpEngine, targetName,
+ contextEngineId, contextName,
nonRepeaters, maxRepetitions, varBinds):
future = asyncio.Future()
self.commandGenerator.sendVarBinds(
@@ -167,12 +86,6 @@ class AbstractBulkCommandGenerator:
maxRepetitions,
varBinds,
self._cbFunWithFuture,
- (targetName, contextEngineId, contextName, nonRepeaters, maxRepetitions, varBinds, { 'future': future })
+ future
)
return future
-
-class BulkCommandGeneratorSingleRun(AbstractBulkCommandGenerator):
- commandGenerator = cmdgen.BulkCommandGeneratorSingleRun()
-
-class BulkCommandGenerator(AbstractBulkCommandGenerator):
- commandGenerator = cmdgen.BulkCommandGenerator()
diff --git a/pysnmp/entity/rfc3413/asyncio/ntforg.py b/pysnmp/entity/rfc3413/asyncio/ntforg.py
index 716e524..6f352ab 100644
--- a/pysnmp/entity/rfc3413/asyncio/ntforg.py
+++ b/pysnmp/entity/rfc3413/asyncio/ntforg.py
@@ -2,6 +2,7 @@
# 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: