From d7534580837445553d8ffdc86fd5a161b9d57af1 Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Sat, 29 Dec 2018 12:48:29 +0100 Subject: Redesigned SMI objects management model (#214) The primary motivation behind this redesign is to allow asynchronous operations between SNMP responder and the data source feeding its MIB. This is achieved by redesigning all `read*`, `write*`, `create*` and `destroy*` methods of the `SNMPv2-SMI` MIB objects to return immediately and deliver their results via a call back. This modification brings significant and backward incompatible changes to the low-level MIB operations. The pysnmp MIB modules compiled for older pysnmp remain compatible. --- examples/smi/agent/custom-managed-object.py | 23 ++-- .../smi/agent/operations-on-managed-objects.py | 121 ++++++++++++++++----- .../asyncore/agent/cmdrsp/alternative-mib-tree.py | 2 +- .../asyncore/agent/cmdrsp/custom-mib-controller.py | 2 +- .../agent/cmdrsp/implementing-snmp-table.py | 2 +- 5 files changed, 110 insertions(+), 40 deletions(-) (limited to 'examples') diff --git a/examples/smi/agent/custom-managed-object.py b/examples/smi/agent/custom-managed-object.py index f1af0ae3..50aee947 100644 --- a/examples/smi/agent/custom-managed-object.py +++ b/examples/smi/agent/custom-managed-object.py @@ -29,8 +29,10 @@ sysLocation, = mibBuilder.importSymbols('SNMPv2-MIB', 'sysLocation') class MySysLocationInstance(MibScalarInstance): # noinspection PyUnusedLocal def readGet(self, varBind, **context): + cbFun = context['cbFun'] + # Just return a custom value - return varBind[0], self.syntax.clone('The Leaky Cauldron') + cbFun((varBind[0], self.syntax.clone('The Leaky Cauldron')), **context) sysLocationInstance = MySysLocationInstance( @@ -51,23 +53,22 @@ if __name__ == '__main__': mibInstrum = instrum.MibInstrumController(mibBuilder) + def cbFun(varBinds, **context): for oid, val in varBinds: if exval.endOfMib.isSameTypeWith(val): - context['state']['stop'] = True + context['app']['stop'] = True print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint())) - context['state']['varBinds'] = varBinds + context['app']['varBinds'] = varBinds + - context = { - 'cbFun': cbFun, - 'state': { - 'varBinds': [((1, 3, 6), None)], - 'stop': False - } + app_context = { + 'varBinds': [((1, 3, 6), None)], + 'stop': False } print('Remote manager read access to MIB instrumentation (table walk)') - while not context['state']['stop']: - mibInstrum.readNextVars(*context['state']['varBinds'], **context) + while not app_context['stop']: + mibInstrum.readNextMibObjects(*app_context['varBinds'], cbFun=cbFun, app=app_context) print('done') diff --git a/examples/smi/agent/operations-on-managed-objects.py b/examples/smi/agent/operations-on-managed-objects.py index bfcd021e..75b9a765 100644 --- a/examples/smi/agent/operations-on-managed-objects.py +++ b/examples/smi/agent/operations-on-managed-objects.py @@ -6,62 +6,131 @@ This script explains how SNMP Agent application manipulates its MIB possibly triggered by SNMP Manager's commands. """# -# SNMP agent backend e.g. Agent access to Managed Objects -from pysnmp.smi import builder, instrum, exval +from pysnmp.smi import builder +from pysnmp.smi import instrum +from pysnmp.smi import exval +from pysnmp.smi import error +from pysnmp import debug -print('Loading MIB modules...'), +#debug.setLogger(debug.Debug('all')) + + +def walkMib(): + def cbFun(varBinds, **context): + err = context.get('error') + if err: + print(err) + + for oid, val in varBinds: + if exval.endOfMib.isSameTypeWith(val): + context['app']['stop'] = True + + elif not (exval.noSuchInstance.isSameTypeWith(val) or + exval.noSuchObject.isSameTypeWith(val)): + print('%s = %s' % ('.'.join([str(x) for x in oid]), + not val.isValue and 'N/A' or val.prettyPrint())) + + context['app']['varBinds'] = varBinds + + app_context = { + 'varBinds': [((1, 3, 6), None)], + 'stop': False + } + + print('Read whole MIB (table walk)') + while not app_context['stop']: + mibInstrum.readNextMibObjects(*app_context['varBinds'], cbFun=cbFun, app=app_context) + + +print('Loading MIB modules...') mibBuilder = builder.MibBuilder().loadModules( 'SNMPv2-MIB', 'SNMP-FRAMEWORK-MIB', 'SNMP-COMMUNITY-MIB' ) -print('done') -print('Building MIB tree...'), +print('Building MIB tree...') mibInstrum = instrum.MibInstrumController(mibBuilder) -print('done') -print('Building table entry index from human-friendly representation...'), +walkMib() + +print('Building table entry index from human-friendly representation...') snmpCommunityEntry, = mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunityEntry' ) instanceId = snmpCommunityEntry.getInstIdFromIndices('my-router') -print('done') + +print('Create/update some of SNMP-COMMUNITY-MIB::snmpCommunityEntry table columns: ') def cbFun(varBinds, **context): + err = context.get('error') + if err: + print(err) + for oid, val in varBinds: print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint())) -print('Create/update SNMP-COMMUNITY-MIB::snmpCommunityEntry table row: ') -mibInstrum.writeVars( + +mibInstrum.writeMibObjects( (snmpCommunityEntry.name + (2,) + instanceId, 'mycomm'), (snmpCommunityEntry.name + (3,) + instanceId, 'mynmsname'), (snmpCommunityEntry.name + (7,) + instanceId, 'volatile'), cbFun=cbFun ) -print('done') + +walkMib() def cbFun(varBinds, **context): + err = context.get('error') + if err: + print(err) + for oid, val in varBinds: - if exval.endOfMib.isSameTypeWith(val): - context['state']['stop'] = True print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint())) - context['state']['varBinds'] = varBinds -context = { - 'cbFun': cbFun, - 'state': { - 'varBinds': [((1, 3, 6), None)], - 'stop': False - } -} +print('Destroy SNMP-COMMUNITY-MIB::snmpCommunityEntry table row via RowStatus column: ') + +mibInstrum.writeMibObjects( + (snmpCommunityEntry.name + (8,) + instanceId, 'destroy'), + cbFun=cbFun +) + +walkMib() + + +def cbFun(varBinds, **context): + err = context.get('errors', None) + if err: + print(err) + for oid, val in varBinds: + print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint())) + + +print('Create SNMP-COMMUNITY-MIB::snmpCommunityEntry table row: ') + +mibInstrum.writeMibObjects( + (snmpCommunityEntry.name + (1,) + instanceId, 'mycomm'), + (snmpCommunityEntry.name + (2,) + instanceId, 'mycomm'), + (snmpCommunityEntry.name + (3,) + instanceId, 'mysecname'), + (snmpCommunityEntry.name + (4,) + instanceId, 'abcdef'), + (snmpCommunityEntry.name + (5,) + instanceId, ''), + (snmpCommunityEntry.name + (6,) + instanceId, 'mytag'), + (snmpCommunityEntry.name + (7,) + instanceId, 'nonVolatile'), + (snmpCommunityEntry.name + (8,) + instanceId, 'createAndGo'), + cbFun=cbFun +) + +walkMib() + +print('Destroy SNMP-COMMUNITY-MIB::snmpCommunityEntry table row via RowStatus column: ') + +mibInstrum.writeMibObjects( + (snmpCommunityEntry.name + (8,) + instanceId, 'destroy'), + cbFun=cbFun +) -print('Read whole MIB (table walk)') -while not context['state']['stop']: - mibInstrum.readNextVars(*context['state']['varBinds'], **context) -print('done') +walkMib() print('Unloading MIB modules...'), mibBuilder.unloadModules() -print('done') diff --git a/examples/v3arch/asyncore/agent/cmdrsp/alternative-mib-tree.py b/examples/v3arch/asyncore/agent/cmdrsp/alternative-mib-tree.py index 5903b54c..2f0947f4 100644 --- a/examples/v3arch/asyncore/agent/cmdrsp/alternative-mib-tree.py +++ b/examples/v3arch/asyncore/agent/cmdrsp/alternative-mib-tree.py @@ -33,7 +33,7 @@ snmpEngine = engine.SnmpEngine() config.addTransport( snmpEngine, udp.domainName, - udp.UdpTransport().openServerMode(('127.0.0.1', 161)) + udp.UdpTransport().openServerMode(('127.0.0.1', 1161)) ) # SNMPv3/USM setup diff --git a/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py b/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py index 7e74df3d..21f86f1d 100644 --- a/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py +++ b/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py @@ -53,7 +53,7 @@ snmpContext = context.SnmpContext(snmpEngine) # any Managed Objects attached. It supports only GET's and # always echos request var-binds in response. class EchoMibInstrumController(instrum.AbstractMibInstrumController): - def readVars(self, *varBinds, **context): + def readMibObjects(self, *varBinds, **context): cbFun = context.get('cbFun') if cbFun: cbFun([(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds], **context) diff --git a/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py b/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py index ea924fc2..333ebad4 100644 --- a/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py +++ b/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py @@ -101,7 +101,7 @@ mibBuilder.exportSymbols( ) rowInstanceId = exampleTableEntry.getInstIdFromIndices('example record one') mibInstrumentation = snmpContext.getMibInstrum() -mibInstrumentation.writeVars( +mibInstrumentation.writeMibObjects( (exampleTableColumn2.name + rowInstanceId, 'my string value'), (exampleTableColumn3.name + rowInstanceId, 123456), (exampleTableStatus.name + rowInstanceId, 'createAndGo') -- cgit v1.2.1