diff options
author | elie <elie> | 2014-11-16 16:14:37 +0000 |
---|---|---|
committer | elie <elie> | 2014-11-16 16:14:37 +0000 |
commit | edff85c75a5ba51c6824f6d09ec55986682db335 (patch) | |
tree | c0216f83de60b93ef9c24ad801a47e2a14308b6e | |
parent | 481200dc56925509a54b89c28d054ba28f4e437c (diff) | |
download | pysnmp-edff85c75a5ba51c6824f6d09ec55986682db335.tar.gz |
asyncio-backed SNMP Applications APIs redesigned for better usability in
form of coroutines
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: |