diff options
-rw-r--r-- | CHANGES.txt | 12 | ||||
-rw-r--r-- | examples/smi/agent/custom-managed-object.py | 13 | ||||
-rw-r--r-- | examples/smi/agent/operations-on-managed-objects.py | 11 | ||||
-rw-r--r-- | examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py | 2 | ||||
-rw-r--r-- | examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py | 6 | ||||
-rw-r--r-- | pysnmp/entity/config.py | 209 | ||||
-rw-r--r-- | pysnmp/entity/rfc3413/cmdrsp.py | 151 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 9 | ||||
-rw-r--r-- | pysnmp/smi/instrum.py | 52 | ||||
-rw-r--r-- | pysnmp/smi/mibs/SNMPv2-SMI.py | 604 |
10 files changed, 661 insertions, 408 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 6d51f9c6..ca6eb6d7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ -Revision 5.0.0, released 2018-03-?? +Revision 5.0.0, released 2018-07-?? ----------------------------------- - SNMPv3 crypto operations that require external dependencies @@ -12,6 +12,16 @@ Revision 5.0.0, released 2018-03-?? Most importantly, the `pysnmp.entity.rfc3413.oneliner` and everything related to (non-standard) UNIX domain socket transport are gone. +- The MIB instrumentation API overhauled in backward incompatible + way: + + - MIB instrumentation methods signatures simplified to accept + just var-binds (as var-arg), the rest of the parameters packed + into opaque kwargs + - CommandResponder application passes `snmpEngine` and optionally + user-supplied `cbCtx` object throughout the MIB instrumentation + methods. The goal is to let MIB objects access/modify whatever + custom Python objects they need while being called back. Revision 4.4.5, released 2018-04-XX ----------------------------------- diff --git a/examples/smi/agent/custom-managed-object.py b/examples/smi/agent/custom-managed-object.py index 0b175193..73bfa836 100644 --- a/examples/smi/agent/custom-managed-object.py +++ b/examples/smi/agent/custom-managed-object.py @@ -28,9 +28,9 @@ sysLocation, = mibBuilder.importSymbols('SNMPv2-MIB', 'sysLocation') # Custom Managed Object class MySysLocationInstance(MibScalarInstance): # noinspection PyUnusedLocal - def readGet(self, name, *args): + def readGet(self, varBind, **context): # Just return a custom value - return name, self.syntax.clone('The Leaky Cauldron') + return varBind[0], self.syntax.clone('The Leaky Cauldron') sysLocationInstance = MySysLocationInstance( @@ -52,9 +52,12 @@ if __name__ == '__main__': mibInstrum = instrum.MibInstrumController(mibBuilder) print('Remote manager read access to MIB instrumentation (table walk)') - oid, val = (), None - while 1: - oid, val = mibInstrum.readNextVars(((oid, val),))[0] + + varBinds = [((), None)] + + while True: + varBinds = mibInstrum.readNextVars(*varBinds) + oid, val = varBinds[0] if exval.endOfMib.isSameTypeWith(val): break print(oid, val.prettyPrint()) diff --git a/examples/smi/agent/operations-on-managed-objects.py b/examples/smi/agent/operations-on-managed-objects.py index 7d1f300c..e1eb52d6 100644 --- a/examples/smi/agent/operations-on-managed-objects.py +++ b/examples/smi/agent/operations-on-managed-objects.py @@ -28,18 +28,19 @@ print('done') print('Create/update SNMP-COMMUNITY-MIB::snmpCommunityEntry table row: ') varBinds = mibInstrum.writeVars( - ((snmpCommunityEntry.name + (2,) + instanceId, 'mycomm'), - (snmpCommunityEntry.name + (3,) + instanceId, 'mynmsname'), - (snmpCommunityEntry.name + (7,) + instanceId, 'volatile')) + (snmpCommunityEntry.name + (2,) + instanceId, 'mycomm'), + (snmpCommunityEntry.name + (3,) + instanceId, 'mynmsname'), + (snmpCommunityEntry.name + (7,) + instanceId, 'volatile') ) 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('done') print('Read whole MIB (table walk)') -oid, val = (), None +varBinds = [((), None)] while True: - oid, val = mibInstrum.readNextVars(((oid, val),))[0] + varBinds = mibInstrum.readNextVars(*varBinds) + oid, val = varBinds[0] if exval.endOfMib.isSameTypeWith(val): break print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint())) diff --git a/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py b/examples/v3arch/asyncore/agent/cmdrsp/custom-mib-controller.py index 1a03e725..94bdb7de 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, acInfo=(None, None)): + def readVars(self, *varBinds, **context): return [(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds] diff --git a/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py b/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py index 0e15599a..ea924fc2 100644 --- a/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py +++ b/examples/v3arch/asyncore/agent/cmdrsp/implementing-snmp-table.py @@ -102,9 +102,9 @@ mibBuilder.exportSymbols( rowInstanceId = exampleTableEntry.getInstIdFromIndices('example record one') mibInstrumentation = snmpContext.getMibInstrum() mibInstrumentation.writeVars( - ((exampleTableColumn2.name + rowInstanceId, 'my string value'), - (exampleTableColumn3.name + rowInstanceId, 123456), - (exampleTableStatus.name + rowInstanceId, 'createAndGo')) + (exampleTableColumn2.name + rowInstanceId, 'my string value'), + (exampleTableColumn3.name + rowInstanceId, 123456), + (exampleTableStatus.name + rowInstanceId, 'createAndGo') ) # --- end of SNMP table population --- diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index d34c3773..ce6e9b07 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -83,17 +83,19 @@ def addV1System(snmpEngine, communityIndex, communityName, contextName = null snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'),) + (snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpCommunityEntry.name + (1,) + tblIdx, communityIndex), - (snmpCommunityEntry.name + (2,) + tblIdx, communityName), - (snmpCommunityEntry.name + (3,) + tblIdx, securityName is not None and securityName or communityIndex), - (snmpCommunityEntry.name + (4,) + tblIdx, contextEngineId), - (snmpCommunityEntry.name + (5,) + tblIdx, contextName), - (snmpCommunityEntry.name + (6,) + tblIdx, transportTag), - (snmpCommunityEntry.name + (7,) + tblIdx, 'nonVolatile'), - (snmpCommunityEntry.name + (8,) + tblIdx, 'createAndGo')) + (snmpCommunityEntry.name + (1,) + tblIdx, communityIndex), + (snmpCommunityEntry.name + (2,) + tblIdx, communityName), + (snmpCommunityEntry.name + (3,) + tblIdx, securityName is not None and securityName or communityIndex), + (snmpCommunityEntry.name + (4,) + tblIdx, contextEngineId), + (snmpCommunityEntry.name + (5,) + tblIdx, contextName), + (snmpCommunityEntry.name + (6,) + tblIdx, transportTag), + (snmpCommunityEntry.name + (7,) + tblIdx, 'nonVolatile'), + (snmpCommunityEntry.name + (8,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -101,7 +103,8 @@ def delV1System(snmpEngine, communityIndex): (snmpCommunityEntry, tblIdx, snmpEngineID) = __cookV1SystemInfo(snmpEngine, communityIndex) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'),) + (snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -143,15 +146,17 @@ def addV3User(snmpEngine, userName, zeroDotZero, = mibBuilder.importSymbols('SNMPv2-SMI', 'zeroDotZero') snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((usmUserEntry.name + (13,) + tblIdx1, 'destroy'),) + (usmUserEntry.name + (13,) + tblIdx1, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((usmUserEntry.name + (2,) + tblIdx1, userName), - (usmUserEntry.name + (3,) + tblIdx1, securityName), - (usmUserEntry.name + (4,) + tblIdx1, zeroDotZero.name), - (usmUserEntry.name + (5,) + tblIdx1, authProtocol), - (usmUserEntry.name + (8,) + tblIdx1, privProtocol), - (usmUserEntry.name + (13,) + tblIdx1, 'createAndGo')) + (usmUserEntry.name + (2,) + tblIdx1, userName), + (usmUserEntry.name + (3,) + tblIdx1, securityName), + (usmUserEntry.name + (4,) + tblIdx1, zeroDotZero.name), + (usmUserEntry.name + (5,) + tblIdx1, authProtocol), + (usmUserEntry.name + (8,) + tblIdx1, privProtocol), + (usmUserEntry.name + (13,) + tblIdx1, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) # Localize keys @@ -177,22 +182,25 @@ def addV3User(snmpEngine, userName, # Commit localized keys snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((pysnmpUsmKeyEntry.name + (1,) + tblIdx1, localAuthKey), - (pysnmpUsmKeyEntry.name + (2,) + tblIdx1, localPrivKey), - (pysnmpUsmKeyEntry.name + (3,) + tblIdx1, hashedAuthPassphrase), - (pysnmpUsmKeyEntry.name + (4,) + tblIdx1, hashedPrivPassphrase)) + (pysnmpUsmKeyEntry.name + (1,) + tblIdx1, localAuthKey), + (pysnmpUsmKeyEntry.name + (2,) + tblIdx1, localPrivKey), + (pysnmpUsmKeyEntry.name + (3,) + tblIdx1, hashedAuthPassphrase), + (pysnmpUsmKeyEntry.name + (4,) + tblIdx1, hashedPrivPassphrase), + **dict(snmpEngine=snmpEngine) ) # Commit passphrases snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'),) + (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), - (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey), - (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey), - (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'createAndGo')) + (pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), + (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey), + (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey), + (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -202,10 +210,12 @@ def delV3User(snmpEngine, (snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(snmpEngine, userName, securityEngineId) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((usmUserEntry.name + (13,) + tblIdx1, 'destroy'),) + (usmUserEntry.name + (13,) + tblIdx1, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'),) + (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'), + **dict(snmpEngine=snmpEngine) ) # Drop all derived rows @@ -216,7 +226,7 @@ def delV3User(snmpEngine, ) while varBinds: varBinds = snmpEngine.msgAndPduDsp.mibInstrumController.readNextVars( - varBinds + *varBinds, **dict(snmpEngine=snmpEngine) ) if varBinds[0][1].isSameTypeWith(rfc1905.endOfMibView): break @@ -249,22 +259,25 @@ def addTargetParams(snmpEngine, name, securityName, securityLevel, mpModel=3): snmpTargetParamsEntry, tblIdx = __cookTargetParamsInfo(snmpEngine, name) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetParamsEntry.name + (7,) + tblIdx, 'destroy'),) + (snmpTargetParamsEntry.name + (7,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetParamsEntry.name + (1,) + tblIdx, name), - (snmpTargetParamsEntry.name + (2,) + tblIdx, mpModel), - (snmpTargetParamsEntry.name + (3,) + tblIdx, securityModel), - (snmpTargetParamsEntry.name + (4,) + tblIdx, securityName), - (snmpTargetParamsEntry.name + (5,) + tblIdx, securityLevel), - (snmpTargetParamsEntry.name + (7,) + tblIdx, 'createAndGo')) + (snmpTargetParamsEntry.name + (1,) + tblIdx, name), + (snmpTargetParamsEntry.name + (2,) + tblIdx, mpModel), + (snmpTargetParamsEntry.name + (3,) + tblIdx, securityModel), + (snmpTargetParamsEntry.name + (4,) + tblIdx, securityName), + (snmpTargetParamsEntry.name + (5,) + tblIdx, securityLevel), + (snmpTargetParamsEntry.name + (7,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) def delTargetParams(snmpEngine, name): snmpTargetParamsEntry, tblIdx = __cookTargetParamsInfo(snmpEngine, name) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetParamsEntry.name + (7,) + tblIdx, 'destroy'),) + (snmpTargetParamsEntry.name + (7,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -299,18 +312,20 @@ def addTargetAddr(snmpEngine, addrName, transportDomain, transportAddress, sourceAddress = TransportAddressIPv6(sourceAddress) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'),) + (snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetAddrEntry.name + (1,) + tblIdx, addrName), - (snmpTargetAddrEntry.name + (2,) + tblIdx, transportDomain), - (snmpTargetAddrEntry.name + (3,) + tblIdx, transportAddress), - (snmpTargetAddrEntry.name + (4,) + tblIdx, timeout), - (snmpTargetAddrEntry.name + (5,) + tblIdx, retryCount), - (snmpTargetAddrEntry.name + (6,) + tblIdx, tagList), - (snmpTargetAddrEntry.name + (7,) + tblIdx, params), - (snmpSourceAddrEntry.name + (1,) + tblIdx, sourceAddress), - (snmpTargetAddrEntry.name + (9,) + tblIdx, 'createAndGo')) + (snmpTargetAddrEntry.name + (1,) + tblIdx, addrName), + (snmpTargetAddrEntry.name + (2,) + tblIdx, transportDomain), + (snmpTargetAddrEntry.name + (3,) + tblIdx, transportAddress), + (snmpTargetAddrEntry.name + (4,) + tblIdx, timeout), + (snmpTargetAddrEntry.name + (5,) + tblIdx, retryCount), + (snmpTargetAddrEntry.name + (6,) + tblIdx, tagList), + (snmpTargetAddrEntry.name + (7,) + tblIdx, params), + (snmpSourceAddrEntry.name + (1,) + tblIdx, sourceAddress), + (snmpTargetAddrEntry.name + (9,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -318,7 +333,8 @@ def delTargetAddr(snmpEngine, addrName): (snmpTargetAddrEntry, snmpSourceAddrEntry, tblIdx) = __cookTargetAddrInfo(snmpEngine, addrName) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'),) + (snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -386,7 +402,8 @@ def addContext(snmpEngine, contextName): vacmContextEntry, = mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry') tblIdx = vacmContextEntry.getInstIdFromIndices(contextName) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmContextEntry.name + (1,) + tblIdx, contextName),) + (vacmContextEntry.name + (1,) + tblIdx, contextName), + ** dict(snmpEngine=snmpEngine) ) @@ -404,13 +421,15 @@ def addVacmGroup(snmpEngine, groupName, securityModel, securityName): (vacmSecurityToGroupEntry, tblIdx) = __cookVacmGroupInfo(snmpEngine, securityModel, securityName) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'),) + (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmSecurityToGroupEntry.name + (1,) + tblIdx, securityModel), - (vacmSecurityToGroupEntry.name + (2,) + tblIdx, securityName), - (vacmSecurityToGroupEntry.name + (3,) + tblIdx, groupName), - (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'createAndGo')) + (vacmSecurityToGroupEntry.name + (1,) + tblIdx, securityModel), + (vacmSecurityToGroupEntry.name + (2,) + tblIdx, securityName), + (vacmSecurityToGroupEntry.name + (3,) + tblIdx, groupName), + (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -419,7 +438,8 @@ def delVacmGroup(snmpEngine, securityModel, securityName): snmpEngine, securityModel, securityName ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'),) + (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -442,17 +462,19 @@ def addVacmAccess(snmpEngine, groupName, contextName, securityModel, addContext(snmpEngine, contextName) # this is leaky snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmAccessEntry.name + (9,) + tblIdx, 'destroy'),) + (vacmAccessEntry.name + (9,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmAccessEntry.name + (1,) + tblIdx, contextName), - (vacmAccessEntry.name + (2,) + tblIdx, securityModel), - (vacmAccessEntry.name + (3,) + tblIdx, securityLevel), - (vacmAccessEntry.name + (4,) + tblIdx, prefix), - (vacmAccessEntry.name + (5,) + tblIdx, readView), - (vacmAccessEntry.name + (6,) + tblIdx, writeView), - (vacmAccessEntry.name + (7,) + tblIdx, notifyView), - (vacmAccessEntry.name + (9,) + tblIdx, 'createAndGo')) + (vacmAccessEntry.name + (1,) + tblIdx, contextName), + (vacmAccessEntry.name + (2,) + tblIdx, securityModel), + (vacmAccessEntry.name + (3,) + tblIdx, securityLevel), + (vacmAccessEntry.name + (4,) + tblIdx, prefix), + (vacmAccessEntry.name + (5,) + tblIdx, readView), + (vacmAccessEntry.name + (6,) + tblIdx, writeView), + (vacmAccessEntry.name + (7,) + tblIdx, notifyView), + (vacmAccessEntry.name + (9,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -462,7 +484,8 @@ def delVacmAccess(snmpEngine, groupName, contextName, securityModel, contextName, securityModel, securityLevel) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmAccessEntry.name + (9,) + tblIdx, 'destroy'),) + (vacmAccessEntry.name + (9,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -480,14 +503,16 @@ def addVacmView(snmpEngine, viewName, viewType, subTree, mask): vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo(snmpEngine, viewName, subTree) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'),) + (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmViewTreeFamilyEntry.name + (1,) + tblIdx, viewName), - (vacmViewTreeFamilyEntry.name + (2,) + tblIdx, subTree), - (vacmViewTreeFamilyEntry.name + (3,) + tblIdx, mask), - (vacmViewTreeFamilyEntry.name + (4,) + tblIdx, viewType), - (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'createAndGo')) + (vacmViewTreeFamilyEntry.name + (1,) + tblIdx, viewName), + (vacmViewTreeFamilyEntry.name + (2,) + tblIdx, subTree), + (vacmViewTreeFamilyEntry.name + (3,) + tblIdx, mask), + (vacmViewTreeFamilyEntry.name + (4,) + tblIdx, viewType), + (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -495,7 +520,8 @@ def delVacmView(snmpEngine, viewName, subTree): vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo(snmpEngine, viewName, subTree) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'),) + (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'), + **dict(snmpEngine=snmpEngine) ) @@ -586,33 +612,39 @@ def addNotificationTarget(snmpEngine, notificationName, paramsName, paramsName, filterSubtree) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'),) + (snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyEntry.name + (2,) + tblIdx1, transportTag), - (snmpNotifyEntry.name + (3,) + tblIdx1, notifyType), - (snmpNotifyEntry.name + (5,) + tblIdx1, 'createAndGo')) + (snmpNotifyEntry.name + (2,) + tblIdx1, transportTag), + (snmpNotifyEntry.name + (3,) + tblIdx1, notifyType), + (snmpNotifyEntry.name + (5,) + tblIdx1, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'destroy'),) + (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterProfileEntry.name + (1,) + tblIdx2, profileName), - (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'createAndGo')) + (snmpNotifyFilterProfileEntry.name + (1,) + tblIdx2, profileName), + (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) if not snmpNotifyFilterEntry: return snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'destroy'),) + (snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterEntry.name + (1,) + tblIdx3, filterSubtree), - (snmpNotifyFilterEntry.name + (2,) + tblIdx3, filterMask), - (snmpNotifyFilterEntry.name + (3,) + tblIdx3, filterType), - (snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'createAndGo')) + (snmpNotifyFilterEntry.name + (1,) + tblIdx3, filterSubtree), + (snmpNotifyFilterEntry.name + (2,) + tblIdx3, filterMask), + (snmpNotifyFilterEntry.name + (3,) + tblIdx3, filterType), + (snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'createAndGo'), + **dict(snmpEngine=snmpEngine) ) @@ -624,18 +656,21 @@ def delNotificationTarget(snmpEngine, notificationName, paramsName, paramsName, filterSubtree) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'),) + (snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'), + **dict(snmpEngine=snmpEngine) ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'destroy'),) + (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'destroy'), + **dict(snmpEngine=snmpEngine) ) if not snmpNotifyFilterEntry: return snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( - ((snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'destroy'),) + (snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'destroy'), + **dict(snmpEngine=snmpEngine) ) diff --git a/pysnmp/entity/rfc3413/cmdrsp.py b/pysnmp/entity/rfc3413/cmdrsp.py index 94b4d45b..3d2cb5ab 100644 --- a/pysnmp/entity/rfc3413/cmdrsp.py +++ b/pysnmp/entity/rfc3413/cmdrsp.py @@ -17,15 +17,16 @@ class CommandResponderBase(object): acmID = 3 # default MIB access control method to use pduTypes = () - def __init__(self, snmpEngine, snmpContext): + def __init__(self, snmpEngine, snmpContext, cbCtx=None): snmpEngine.msgAndPduDsp.registerContextEngineId( snmpContext.contextEngineId, self.pduTypes, self.processPdu ) self.snmpContext = snmpContext + self.cbCtx = cbCtx self.__pendingReqs = {} - def handleMgmtOperation(self, snmpEngine, stateReference, contextName, - PDU, acInfo): + def handleMgmtOperation(self, snmpEngine, stateReference, + contextName, PDU, acCtx): pass def close(self, snmpEngine): @@ -36,9 +37,16 @@ class CommandResponderBase(object): def sendVarBinds(self, snmpEngine, stateReference, errorStatus, errorIndex, varBinds): - (messageProcessingModel, securityModel, securityName, - securityLevel, contextEngineId, contextName, - pduVersion, PDU, origPdu, maxSizeResponseScopedPDU, + (messageProcessingModel, + securityModel, + securityName, + securityLevel, + contextEngineId, + contextName, + pduVersion, + PDU, + origPdu, + maxSizeResponseScopedPDU, statusInformation) = self.__pendingReqs[stateReference] v2c.apiPDU.setErrorStatus(PDU, errorStatus) @@ -53,9 +61,16 @@ class CommandResponderBase(object): self.sendPdu(snmpEngine, stateReference, PDU) def sendPdu(self, snmpEngine, stateReference, PDU): - (messageProcessingModel, securityModel, securityName, - securityLevel, contextEngineId, contextName, - pduVersion, _, origPdu, maxSizeResponseScopedPDU, + (messageProcessingModel, + securityModel, + securityName, + securityLevel, + contextEngineId, + contextName, + pduVersion, + _, + origPdu, + maxSizeResponseScopedPDU, statusInformation) = self.__pendingReqs[stateReference] # Agent-side API complies with SMIv2 @@ -132,9 +147,8 @@ class CommandResponderBase(object): 'processPdu: stateReference %s, varBinds %s' % (stateReference, varBinds)) try: - self.handleMgmtOperation(snmpEngine, stateReference, - contextName, PDU, - (self.__verifyAccess, snmpEngine)) + self.handleMgmtOperation(snmpEngine, stateReference, contextName, PDU) + # SNMPv2 SMI exceptions except pysnmp.smi.error.GenError: errorIndication = sys.exc_info()[1] @@ -185,18 +199,29 @@ class CommandResponderBase(object): self.releaseStateInformation(stateReference) - def __verifyAccess(self, name, syntax, idx, viewType, acCtx): - snmpEngine = acCtx + @classmethod + def verifyAccess(cls, viewType, varBind, **context): + name, val = varBind + + snmpEngine = context['snmpEngine'] + execCtx = snmpEngine.observer.getExecutionContext('rfc3412.receiveMessage:request') - (securityModel, securityName, securityLevel, contextName, - pduType) = (execCtx['securityModel'], execCtx['securityName'], - execCtx['securityLevel'], execCtx['contextName'], + (securityModel, + securityName, + securityLevel, + contextName, + pduType) = (execCtx['securityModel'], + execCtx['securityName'], + execCtx['securityLevel'], + execCtx['contextName'], execCtx['pdu'].getTagSet()) + try: - snmpEngine.accessControlModel[self.acmID].isAccessAllowed( + snmpEngine.accessControlModel[cls.acmID].isAccessAllowed( snmpEngine, securityModel, securityName, securityLevel, viewType, contextName, name ) + # Map ACM errors onto SMI ones except error.StatusInformation: statusInformation = sys.exc_info()[1] @@ -207,41 +232,48 @@ class CommandResponderBase(object): if (errorIndication == errind.noSuchView or errorIndication == errind.noAccessEntry or errorIndication == errind.noGroupName): - raise pysnmp.smi.error.AuthorizationError(name=name, idx=idx) + raise pysnmp.smi.error.AuthorizationError(name=name, idx=context.get('idx')) + elif errorIndication == errind.otherError: - raise pysnmp.smi.error.GenError(name=name, idx=idx) + raise pysnmp.smi.error.GenError(name=name, idx=context.get('idx')) + elif errorIndication == errind.noSuchContext: snmpUnknownContexts, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-TARGET-MIB', 'snmpUnknownContexts') snmpUnknownContexts.syntax += 1 # Request REPORT generation - raise pysnmp.smi.error.GenError(name=name, idx=idx, + raise pysnmp.smi.error.GenError(name=name, idx=context.get('idx'), oid=snmpUnknownContexts.name, val=snmpUnknownContexts.syntax) + elif errorIndication == errind.notInView: - return 1 + return True + else: raise error.ProtocolError('Unknown ACM error %s' % errorIndication) else: # rfc2576: 4.1.2.1 - if (securityModel == 1 and syntax is not None and - self._counter64Type == syntax.getTagSet() and - self._getNextRequestType == pduType): + if (securityModel == 1 and val is not None and + cls._counter64Type == val.getTagSet() and + cls._getNextRequestType == pduType): # This will cause MibTree to skip this OID-value - raise pysnmp.smi.error.NoAccessError(name=name, idx=idx) + raise pysnmp.smi.error.NoAccessError(name=name, idx=context.get('idx')) class GetCommandResponder(CommandResponderBase): pduTypes = (rfc1905.GetRequestPDU.tagSet,) # rfc1905: 4.2.1 - def handleMgmtOperation(self, snmpEngine, stateReference, - contextName, PDU, acInfo): - (acFun, acCtx) = acInfo + def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU): # rfc1905: 4.2.1.1 mgmtFun = self.snmpContext.getMibInstrum(contextName).readVars - self.sendVarBinds(snmpEngine, stateReference, 0, 0, - mgmtFun(v2c.apiPDU.getVarBinds(PDU), (acFun, acCtx))) + varBinds = v2c.apiPDU.getVarBinds(PDU) + + context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx) + + rspVarBinds = mgmtFun(*varBinds, **context) + + self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds) self.releaseStateInformation(stateReference) @@ -249,21 +281,26 @@ class NextCommandResponder(CommandResponderBase): pduTypes = (rfc1905.GetNextRequestPDU.tagSet,) # rfc1905: 4.2.2 - def handleMgmtOperation(self, snmpEngine, stateReference, - contextName, PDU, acInfo): - (acFun, acCtx) = acInfo + def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU): # rfc1905: 4.2.2.1 mgmtFun = self.snmpContext.getMibInstrum(contextName).readNextVars + varBinds = v2c.apiPDU.getVarBinds(PDU) + + context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx) + while True: - rspVarBinds = mgmtFun(varBinds, (acFun, acCtx)) + rspVarBinds = mgmtFun(*varBinds, **context) + try: self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds) + except error.StatusInformation: idx = sys.exc_info()[1]['idx'] varBinds[idx] = (rspVarBinds[idx][0], varBinds[idx][1]) else: break + self.releaseStateInformation(stateReference) @@ -272,12 +309,11 @@ class BulkCommandResponder(CommandResponderBase): maxVarBinds = 64 # rfc1905: 4.2.3 - def handleMgmtOperation(self, snmpEngine, stateReference, - contextName, PDU, acInfo): - (acFun, acCtx) = acInfo + def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU): nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(PDU) if nonRepeaters < 0: nonRepeaters = 0 + maxRepetitions = v2c.apiBulkPDU.getMaxRepetitions(PDU) if maxRepetitions < 0: maxRepetitions = 0 @@ -295,14 +331,19 @@ class BulkCommandResponder(CommandResponderBase): mgmtFun = self.snmpContext.getMibInstrum(contextName).readNextVars + context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx) + if N: - rspVarBinds = mgmtFun(reqVarBinds[:N], (acFun, acCtx)) + # TODO(etingof): manage all PDU var-binds in a single call + rspVarBinds = mgmtFun(*reqVarBinds[:N], **context) + else: rspVarBinds = [] varBinds = reqVarBinds[-R:] + while M and R: - rspVarBinds.extend(mgmtFun(varBinds, (acFun, acCtx))) + rspVarBinds.extend(mgmtFun(*varBinds, **context)) varBinds = rspVarBinds[-R:] M -= 1 @@ -317,18 +358,28 @@ class SetCommandResponder(CommandResponderBase): pduTypes = (rfc1905.SetRequestPDU.tagSet,) # rfc1905: 4.2.5 - def handleMgmtOperation(self, snmpEngine, stateReference, - contextName, PDU, acInfo): - (acFun, acCtx) = acInfo + def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU): mgmtFun = self.snmpContext.getMibInstrum(contextName).writeVars + + varBinds = v2c.apiPDU.getVarBinds(PDU) + + instrumError = None + + context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx) + # rfc1905: 4.2.5.1-13 try: - self.sendVarBinds(snmpEngine, stateReference, 0, 0, - mgmtFun(v2c.apiPDU.getVarBinds(PDU), - (acFun, acCtx))) - self.releaseStateInformation(stateReference) + rspVarBinds = mgmtFun(*varBinds, **context) + except (pysnmp.smi.error.NoSuchObjectError, pysnmp.smi.error.NoSuchInstanceError): - e = pysnmp.smi.error.NotWritableError() - e.update(sys.exc_info()[1]) - raise e + instrumError = pysnmp.smi.error.NotWritableError() + instrumError.update(sys.exc_info()[1]) + + else: + self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds) + + self.releaseStateInformation(stateReference) + + if instrumError: + raise instrumError diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index b7760e4b..f3324961 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -138,8 +138,9 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): pysnmpUsmKeyAuthLocalized, usmUserPrivProtocol, pysnmpUsmKeyPrivLocalized) - def __cloneUserInfo(self, mibInstrumController, securityEngineID, - userName): + def __cloneUserInfo(self, snmpEngine, securityEngineID, userName): + mibInstrumController = snmpEngine.msgAndPduDsp.mibInstrumController + snmpEngineID, = mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID' ) @@ -169,7 +170,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # New row mibInstrumController.writeVars( - ((usmUserEntry.name + (13,) + tblIdx2, 4),) + (usmUserEntry.name + (13,) + tblIdx2, 4), **dict(snmpEngine=snmpEngine) ) # Set user&securityNames @@ -273,7 +274,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__cloneUserInfo( - snmpEngine.msgAndPduDsp.mibInstrumController, + snmpEngine, securityEngineID, self.__sec2usr(snmpEngine, securityName) ) diff --git a/pysnmp/smi/instrum.py b/pysnmp/smi/instrum.py index bd1444a9..84902025 100644 --- a/pysnmp/smi/instrum.py +++ b/pysnmp/smi/instrum.py @@ -13,13 +13,13 @@ __all__ = ['AbstractMibInstrumController', 'MibInstrumController'] class AbstractMibInstrumController(object): - def readVars(self, varBinds, acInfo=(None, None)): + def readVars(self, *varBinds, **context): raise error.NoSuchInstanceError(idx=0) - def readNextVars(self, varBinds, acInfo=(None, None)): + def readNextVars(self, *varBinds, **context): raise error.EndOfMibViewError(idx=0) - def writeVars(self, varBinds, acInfo=(None, None)): + def writeVars(self, *varBinds, **context): raise error.NoSuchObjectError(idx=0) @@ -183,19 +183,22 @@ class MibInstrumController(AbstractMibInstrumController): # MIB instrumentation - def flipFlopFsm(self, fsmTable, inputVarBinds, acInfo): + def flipFlopFsm(self, fsmTable, *varBinds, **context): self.__indexMib() - debug.logger & debug.flagIns and debug.logger('flipFlopFsm: input var-binds %r' % (inputVarBinds,)) + + debug.logger & debug.flagIns and debug.logger('flipFlopFsm: input var-binds %r' % (varBinds,)) + mibTree, = self.mibBuilder.importSymbols('SNMPv2-SMI', 'iso') + outputVarBinds = [] state, status = 'start', 'ok' - origExc = None + origExc = origTraceback = None while True: - k = (state, status) + k = state, status if k in fsmTable: fsmState = fsmTable[k] else: - k = ('*', status) + k = '*', status if k in fsmTable: fsmState = fsmTable[k] else: @@ -208,32 +211,36 @@ class MibInstrumController(AbstractMibInstrumController): status = 'ok' if state == 'stop': break - idx = 0 - for name, val in inputVarBinds: - f = getattr(mibTree, state, None) - if f is None: + + for idx, (name, val) in enumerate(varBinds): + mgmtFun = getattr(mibTree, state, None) + if not mgmtFun: raise error.SmiError( 'Unsupported state handler %s at %s' % (state, self) ) + + context['idx'] = idx + try: # Convert to tuple to avoid ObjectName instantiation # on subscription - rval = f(tuple(name), val, idx, acInfo) + rval = mgmtFun((tuple(name), val), **context) + except error.SmiError: exc_t, exc_v, exc_tb = sys.exc_info() debug.logger & debug.flagIns and debug.logger( 'flipFlopFsm: fun %s exception %s for %s=%r with traceback: %s' % ( - f, exc_t, name, val, traceback.format_exception(exc_t, exc_v, exc_tb))) + mgmtFun, exc_t, name, val, traceback.format_exception(exc_t, exc_v, exc_tb))) if origExc is None: # Take the first exception origExc, origTraceback = exc_v, exc_tb status = 'err' break else: debug.logger & debug.flagIns and debug.logger( - 'flipFlopFsm: fun %s suceeded for %s=%r' % (f, name, val)) + 'flipFlopFsm: fun %s suceeded for %s=%r' % (mgmtFun, name, val)) if rval is not None: outputVarBinds.append((rval[0], rval[1])) - idx += 1 + if origExc: if sys.version_info[0] <= 2: raise origExc @@ -244,13 +251,14 @@ class MibInstrumController(AbstractMibInstrumController): # Break cycle between locals and traceback object # (seems to be irrelevant on Py3 but just in case) del origTraceback + return outputVarBinds - def readVars(self, varBinds, acInfo=(None, None)): - return self.flipFlopFsm(self.fsmReadVar, varBinds, acInfo) + def readVars(self, *varBinds, **context): + return self.flipFlopFsm(self.fsmReadVar, *varBinds, **context) - def readNextVars(self, varBinds, acInfo=(None, None)): - return self.flipFlopFsm(self.fsmReadNextVar, varBinds, acInfo) + def readNextVars(self, *varBinds, **context): + return self.flipFlopFsm(self.fsmReadNextVar, *varBinds, **context) - def writeVars(self, varBinds, acInfo=(None, None)): - return self.flipFlopFsm(self.fsmWriteVar, varBinds, acInfo) + def writeVars(self, *varBinds, **context): + return self.flipFlopFsm(self.fsmWriteVar, *varBinds, **context) diff --git a/pysnmp/smi/mibs/SNMPv2-SMI.py b/pysnmp/smi/mibs/SNMPv2-SMI.py index abd64ddc..b5d69cf0 100644 --- a/pysnmp/smi/mibs/SNMPv2-SMI.py +++ b/pysnmp/smi/mibs/SNMPv2-SMI.py @@ -371,16 +371,16 @@ class MibTree(ObjectType): # NoSuchInstanceError exception. # - def getBranch(self, name, idx): + def getBranch(self, name, **context): """Return a branch of this tree where the 'name' OID may reside""" for keyLen in self._vars.getKeysLens(): subName = name[:keyLen] if subName in self._vars: return self._vars[subName] - raise error.NoSuchObjectError(name=name, idx=idx) + raise error.NoSuchObjectError(name=name, idx=context.get('idx')) - def getNextBranch(self, name, idx=None): + def getNextBranch(self, name, **context): # Start from the beginning if self._vars: first = list(self._vars.keys())[0] @@ -392,143 +392,178 @@ class MibTree(ObjectType): try: return self._vars[self._vars.nextKey(name)] except KeyError: - raise error.NoSuchObjectError(idx=idx, name=name) + raise error.NoSuchObjectError(name=name, idx=context.get('idx')) - def getNode(self, name, idx=None): + def getNode(self, name, **context): """Return tree node found by name""" if name == self.name: return self else: - return self.getBranch(name, idx).getNode(name, idx) + return self.getBranch(name, **context).getNode(name, **context) - def getNextNode(self, name, idx=None): + def getNextNode(self, name, **context): """Return tree node next to name""" try: - nextNode = self.getBranch(name, idx) + nextNode = self.getBranch(name, **context) except (error.NoSuchInstanceError, error.NoSuchObjectError): - return self.getNextBranch(name, idx) + return self.getNextBranch(name, **context) else: try: - return nextNode.getNextNode(name, idx) + return nextNode.getNextNode(name, **context) except (error.NoSuchInstanceError, error.NoSuchObjectError): try: return self._vars[self._vars.nextKey(nextNode.name)] except KeyError: - raise error.NoSuchObjectError(idx=idx, name=name) + raise error.NoSuchObjectError(name=name, idx=context.get('idx')) # MIB instrumentation # Read operation - def readTest(self, name, val, idx, acInfo): - (acFun, acCtx) = acInfo + def readTest(self, varBind, **context): + name, val = varBind + if name == self.name: + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readonly', - 'readwrite', 'readcreate') or \ - acFun(name, self.syntax, idx, 'read', acCtx): - raise error.NoAccessError(idx=idx, name=name) + if (self.maxAccess not in ('readonly', 'readwrite', 'readcreate') or + acFun('read', (name, self.syntax), **context)): + raise error.NoAccessError(name=name, idx=context.get('idx')) else: try: - node = self.getBranch(name, idx) + node = self.getBranch(name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): return # missing object is not an error here + else: - node.readTest(name, val, idx, acInfo) + node.readTest(varBind, **context) + + def readGet(self, varBind, **context): + name, val = varBind - def readGet(self, name, val, idx, acInfo): try: - node = self.getBranch(name, idx) + node = self.getBranch(name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): return name, exval.noSuchObject + else: - return node.readGet(name, val, idx, acInfo) + return node.readGet(varBind, **context) # Read next operation is subtree-specific depthFirst, breadthFirst = 0, 1 - def readTestNext(self, name, val, idx, acInfo, oName=None): - if oName is None: - oName = name - topOfTheMib = True - else: - topOfTheMib = False + def readTestNext(self, varBind, **context): + name, val = varBind + + topOfTheMib = context.get('oName') is None + if topOfTheMib: + context['oName'] = name + nextName = name direction = self.depthFirst - while 1: # XXX linear search here + + while True: # NOTE(etingof): linear search here if direction == self.depthFirst: direction = self.breadthFirst try: - node = self.getBranch(nextName, idx) + node = self.getBranch(nextName, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): continue + else: try: - node = self.getNextBranch(nextName, idx) + node = self.getNextBranch(nextName, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): if topOfTheMib: return raise + direction = self.depthFirst nextName = node.name + try: - return node.readTestNext(nextName, val, idx, acInfo, oName) + return node.readTestNext(varBind, **context) + except (error.NoAccessError, error.NoSuchInstanceError, error.NoSuchObjectError): pass - def readGetNext(self, name, val, idx, acInfo, oName=None): - if oName is None: - oName = name - topOfTheMib = True - else: - topOfTheMib = False + def readGetNext(self, varBind, **context): + name, val = varBind + + topOfTheMib = context.get('oName') is None + if topOfTheMib: + context['oName'] = name + nextName = name direction = self.depthFirst - while True: # XXX linear search ahead! + + while True: # NOTE(etingof): linear search ahead! if direction == self.depthFirst: direction = self.breadthFirst try: - node = self.getBranch(nextName, idx) + node = self.getBranch(nextName, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): continue + else: try: - node = self.getNextBranch(nextName, idx) + node = self.getNextBranch(nextName, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): if topOfTheMib: return name, exval.endOfMib raise + direction = self.depthFirst nextName = node.name + try: - return node.readGetNext(nextName, val, idx, acInfo, oName) + return node.readGetNext((nextName, val), **context) + except (error.NoAccessError, error.NoSuchInstanceError, error.NoSuchObjectError): pass # Write operation - def writeTest(self, name, val, idx, acInfo): - acFun, acCtx = acInfo + def writeTest(self, varBind, **context): + name, val = varBind + if name == self.name: # Make sure variable is writable + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readwrite', 'readcreate') or \ - acFun(name, self.syntax, idx, 'write', acCtx): - raise error.NotWritableError(idx=idx, name=name) + if (self.maxAccess not in ('readwrite', 'readcreate') or + acFun('write', (name, self.syntax), **context)): + raise error.NotWritableError(name=name, idx=context.get('idx')) else: - node = self.getBranch(name, idx) - node.writeTest(name, val, idx, acInfo) + node = self.getBranch(name, **context) + node.writeTest(varBind, **context) - def writeCommit(self, name, val, idx, acInfo): - self.getBranch(name, idx).writeCommit(name, val, idx, acInfo) + def writeCommit(self, varBind, **context): + name, val = varBind + + node = self.getBranch(name, **context) + node.writeCommit(varBind, **context) + + def writeCleanup(self, varBind, **context): + name, val = varBind - def writeCleanup(self, name, val, idx, acInfo): self.branchVersionId += 1 - self.getBranch(name, idx).writeCleanup(name, val, idx, acInfo) - def writeUndo(self, name, val, idx, acInfo): - self.getBranch(name, idx).writeUndo(name, val, idx, acInfo) + node = self.getBranch(name, **context) + node.writeCleanup(varBind, **context) + + def writeUndo(self, varBind, **context): + name, val = varBind + + node = self.getBranch(name, **context) + node.writeUndo(varBind, **context) class MibScalar(MibTree): @@ -541,85 +576,104 @@ class MibScalar(MibTree): # Missing branches are indicated by the NoSuchInstanceError exception. # - def getBranch(self, name, idx): + def getBranch(self, name, **context): try: - return MibTree.getBranch(self, name, idx) + return MibTree.getBranch(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNextBranch(self, name, idx=None): + def getNextBranch(self, name, **context): try: - return MibTree.getNextBranch(self, name, idx) + return MibTree.getNextBranch(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNode(self, name, idx=None): + def getNode(self, name, **context): try: - return MibTree.getNode(self, name, idx) + return MibTree.getNode(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNextNode(self, name, idx=None): + def getNextNode(self, name, **context): try: - return MibTree.getNextNode(self, name, idx) + return MibTree.getNextNode(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) # MIB instrumentation methods # Read operation - def readTest(self, name, val, idx, acInfo): - (acFun, acCtx) = acInfo + def readTest(self, varBind, **context): + name, val = varBind + if name == self.name: - raise error.NoAccessError(idx=idx, name=name) + raise error.NoAccessError(name=name, idx=context.get('idx')) + + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readonly', 'readwrite', - 'readcreate') or \ - acFun(name, self.syntax, idx, 'read', acCtx): - raise error.NoAccessError(idx=idx, name=name) - MibTree.readTest(self, name, val, idx, acInfo) + if (self.maxAccess not in ('readonly', 'readwrite', 'readcreate') or + acFun('read', (name, self.syntax), **context)): + raise error.NoAccessError(name=name, idx=context.get('idx')) + + MibTree.readTest(self, varBind, **context) + + def readGet(self, varBind, **context): + name, val = varBind - def readGet(self, name, val, idx, acInfo): try: - node = self.getBranch(name, idx) + node = self.getBranch(name, **context) + except error.NoSuchInstanceError: return name, exval.noSuchInstance + else: - return node.readGet(name, val, idx, acInfo) + return node.readGet(varBind, **context) + + def readTestNext(self, varBind, **context): + name, val = varBind - def readTestNext(self, name, val, idx, acInfo, oName=None): - (acFun, acCtx) = acInfo + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readonly', 'readwrite', - 'readcreate') or \ - acFun(name, self.syntax, idx, 'read', acCtx): - raise error.NoAccessError(idx=idx, name=name) - MibTree.readTestNext(self, name, val, idx, acInfo, oName) - - def readGetNext(self, name, val, idx, acInfo, oName=None): - (acFun, acCtx) = acInfo + if (self.maxAccess not in ('readonly', 'readwrite', 'readcreate') or + acFun('read', (name, self.syntax), **context)): + raise error.NoAccessError(name=name, idx=context.get('idx')) + + MibTree.readTestNext(self, varBind, **context) + + def readGetNext(self, varBind, **context): + name, val = varBind + # have to duplicate AC here as *Next code above treats # noAccess as a noSuchObject at the Test stage, goes on # to Reading + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readonly', 'readwrite', - 'readcreate') or \ - acFun(name, self.syntax, idx, 'read', acCtx): - raise error.NoAccessError(idx=idx, name=name) - return MibTree.readGetNext(self, name, val, idx, acInfo, oName) + if (self.maxAccess not in ('readonly', 'readwrite', 'readcreate') or + acFun('read', (name, self.syntax), **context)): + raise error.NoAccessError(name=name, idx=context.get('idx')) + + return MibTree.readGetNext(self, varBind, **context) # Two-phase commit implementation - def writeTest(self, name, val, idx, acInfo): - acFun, acCtx = acInfo + def writeTest(self, varBind, **context): + name, val = varBind + if name == self.name: - raise error.NoAccessError(idx=idx, name=name) + raise error.NoAccessError(name=name, idx=context.get('idx')) + + acFun = context.get('acFun') if acFun: - if self.maxAccess not in ('readwrite', 'readcreate') or \ - acFun(name, self.syntax, idx, 'write', acCtx): - raise error.NotWritableError(idx=idx, name=name) - MibTree.writeTest(self, name, val, idx, acInfo) + if (self.maxAccess not in ('readwrite', 'readcreate') or + acFun('write', (name, self.syntax), **context)): + raise error.NotWritableError(name=name, idx=context.get('idx')) + + MibTree.writeTest(self, varBind, **context) class MibScalarInstance(MibTree): @@ -636,18 +690,20 @@ class MibScalarInstance(MibTree): # # noinspection PyUnusedLocal - def getValue(self, name, idx): + def getValue(self, name, **context): debug.logger & debug.flagIns and debug.logger('getValue: returning %r for %s' % (self.syntax, self.name)) return self.syntax.clone() - def setValue(self, value, name, idx): + def setValue(self, value, name, **context): if value is None: value = univ.noValue + try: if hasattr(self.syntax, 'setValue'): return self.syntax.setValue(value) else: return self.syntax.clone(value) + except PyAsn1Error: exc_t, exc_v, exc_tb = sys.exc_info() debug.logger & debug.flagIns and debug.logger('setValue: %s=%r failed with traceback %s' % ( @@ -655,7 +711,7 @@ class MibScalarInstance(MibTree): if isinstance(exc_v, error.TableRowManagement): raise exc_v else: - raise error.WrongValueError(idx=idx, name=name, msg=exc_v) + raise error.WrongValueError(name=name, idx=context.get('idx'), msg=exc_v) # # Subtree traversal @@ -663,62 +719,80 @@ class MibScalarInstance(MibTree): # Missing branches are indicated by the NoSuchInstanceError exception. # - def getBranch(self, name, idx): + def getBranch(self, name, **context): try: - return MibTree.getBranch(self, name, idx) + return MibTree.getBranch(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNextBranch(self, name, idx=None): + def getNextBranch(self, name, **context): try: - return MibTree.getNextBranch(self, name, idx) + return MibTree.getNextBranch(self, name, **context) + except (error.NoSuchInstanceError, error.NoSuchObjectError): - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNode(self, name, idx=None): + def getNode(self, name, **context): # Recursion terminator if name == self.name: return self - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def getNextNode(self, name, idx=None): - raise error.NoSuchInstanceError(idx=idx, name=name) + def getNextNode(self, name, **context): + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) # MIB instrumentation methods # Read operation - def readTest(self, name, val, idx, acInfo): + def readTest(self, varBind, **context): + name, val = varBind + if name != self.name: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) + + def readGet(self, varBind, **context): + name, val = varBind - def readGet(self, name, val, idx, acInfo): # Return current variable (name, value) if name == self.name: debug.logger & debug.flagIns and debug.logger('readGet: %s=%r' % (self.name, self.syntax)) - return self.name, self.getValue(name, idx) + return self.name, self.getValue(name, **context) else: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) + + def readTestNext(self, varBind, **context): + name, val = varBind + + oName = context.get('oName') - def readTestNext(self, name, val, idx, acInfo, oName=None): if name != self.name or name <= oName: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) + + def readGetNext(self, varBind, **context): + name, val = varBind + + oName = context.get('oName') - def readGetNext(self, name, val, idx, acInfo, oName=None): if name == self.name and name > oName: debug.logger & debug.flagIns and debug.logger('readGetNext: %s=%r' % (self.name, self.syntax)) - return self.readGet(name, val, idx, acInfo) + return self.readGet(varBind, **context) + else: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) # Write operation: two-phase commit # noinspection PyAttributeOutsideInit - def writeTest(self, name, val, idx, acInfo): + def writeTest(self, varBind, **context): + name, val = varBind + # Make sure write's allowed if name == self.name: try: - self.__newSyntax = self.setValue(val, name, idx) + self.__newSyntax = self.setValue(val, name, **context) + except error.MibOperationError: # SMI exceptions may carry additional content why = sys.exc_info()[1] @@ -726,11 +800,11 @@ class MibScalarInstance(MibTree): self.__newSyntax = why['syntax'] raise why else: - raise error.WrongValueError(idx=idx, name=name, msg=sys.exc_info()[1]) + raise error.WrongValueError(name=name, idx=context.get('idx'), msg=sys.exc_info()[1]) else: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def writeCommit(self, name, val, idx, acInfo): + def writeCommit(self, varBind, **context): # Backup original value if self.__oldSyntax is None: self.__oldSyntax = self.syntax @@ -738,14 +812,14 @@ class MibScalarInstance(MibTree): self.syntax = self.__newSyntax # noinspection PyAttributeOutsideInit - def writeCleanup(self, name, val, idx, acInfo): + def writeCleanup(self, varBind, **context): self.branchVersionId += 1 debug.logger & debug.flagIns and debug.logger('writeCleanup: %s=%r' % (name, val)) # Drop previous value self.__newSyntax = self.__oldSyntax = None # noinspection PyAttributeOutsideInit - def writeUndo(self, name, val, idx, acInfo): + def writeUndo(self, varBind, **context): # Revive previous value self.syntax = self.__oldSyntax self.__newSyntax = self.__oldSyntax = None @@ -755,57 +829,70 @@ class MibScalarInstance(MibTree): # Create operation # noinspection PyUnusedLocal,PyAttributeOutsideInit - def createTest(self, name, val, idx, acInfo): + def createTest(self, varBind, **context): + name, val = varBind + if name == self.name: try: - self.__newSyntax = self.setValue(val, name, idx) + self.__newSyntax = self.setValue(val, name, **context) + except error.MibOperationError: # SMI exceptions may carry additional content why = sys.exc_info()[1] if 'syntax' in why: self.__newSyntax = why['syntax'] else: - raise error.WrongValueError(idx=idx, name=name, msg=sys.exc_info()[1]) + raise error.WrongValueError(name=name, idx=context.get('idx'), msg=sys.exc_info()[1]) else: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) + + def createCommit(self, varBind, **context): + name, val = varBind - def createCommit(self, name, val, idx, acInfo): if val is not None: - self.writeCommit(name, val, idx, acInfo) + self.writeCommit(varBind, **context) - def createCleanup(self, name, val, idx, acInfo): + def createCleanup(self, varBind, **context): self.branchVersionId += 1 + name, val = varBind + debug.logger & debug.flagIns and debug.logger('createCleanup: %s=%r' % (name, val)) + if val is not None: - self.writeCleanup(name, val, idx, acInfo) + self.writeCleanup(varBind, **context) + + def createUndo(self, varBind, **context): + name, val = varBind - def createUndo(self, name, val, idx, acInfo): if val is not None: - self.writeUndo(name, val, idx, acInfo) + self.writeUndo(varBind, **context) # Destroy operation # noinspection PyUnusedLocal,PyAttributeOutsideInit - def destroyTest(self, name, val, idx, acInfo): + def destroyTest(self, varBind, **context): + name, val = varBind + if name == self.name: try: - self.__newSyntax = self.setValue(val, name, idx) + self.__newSyntax = self.setValue(val, name, **context) + except error.MibOperationError: # SMI exceptions may carry additional content why = sys.exc_info()[1] if 'syntax' in why: self.__newSyntax = why['syntax'] else: - raise error.NoSuchInstanceError(idx=idx, name=name) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) - def destroyCommit(self, name, val, idx, acInfo): + def destroyCommit(self, varBind, **context): pass # noinspection PyUnusedLocal - def destroyCleanup(self, name, val, idx, acInfo): + def destroyCleanup(self, varBind, **context): self.branchVersionId += 1 - def destroyUndo(self, name, val, idx, acInfo): + def destroyUndo(self, varBind, **context): pass @@ -827,10 +914,10 @@ class MibTableColumn(MibScalar): # Missing leaves are indicated by the NoSuchInstanceError exception. # - def getBranch(self, name, idx): + def getBranch(self, name, **context): if name in self._vars: return self._vars[name] - raise error.NoSuchInstanceError(name=name, idx=idx) + raise error.NoSuchInstanceError(name=name, idx=context.get('idx')) def setProtoInstance(self, protoInstance): self.protoInstance = protoInstance @@ -839,50 +926,63 @@ class MibTableColumn(MibScalar): # machine for clarity). Also, it might be a good idea to inidicate # defaulted cols creation in a clearer way than just a val == None. - def createTest(self, name, val, idx, acInfo): - (acFun, acCtx) = acInfo + def createTest(self, varBind, **context): + name, val = varBind + # Make sure creation allowed, create a new column instance but # do not replace the old one if name == self.name: - raise error.NoAccessError(idx=idx, name=name) + raise error.NoAccessError(name=name, idx=context.get('idx')) + + acFun = context.get('acFun') if acFun: - if val is not None and self.maxAccess != 'readcreate' or \ - acFun(name, self.syntax, idx, 'write', acCtx): + if (val is not None and self.maxAccess != 'readcreate' or + acFun('write', (name, self.syntax), **context)): debug.logger & debug.flagACL and debug.logger( 'createTest: %s=%r %s at %s' % (name, val, self.maxAccess, self.name)) - raise error.NoCreationError(idx=idx, name=name) + raise error.NoCreationError(name=name, idx=context.get('idx')) + # Create instances if either it does not yet exist (row creation) # or a value is passed (multiple OIDs in SET PDU) if val is None and name in self.__createdInstances: return + self.__createdInstances[name] = self.protoInstance( self.name, name[len(self.name):], self.syntax.clone() ) - self.__createdInstances[name].createTest(name, val, idx, acInfo) - def createCommit(self, name, val, idx, acInfo): + self.__createdInstances[name].createTest(varBind, **context) + + def createCommit(self, varBind, **context): + name, val = varBind + # Commit new instance value if name in self._vars: # XXX if name in self.__createdInstances: - self._vars[name].createCommit(name, val, idx, acInfo) + self._vars[name].createCommit(varBind, **context) return - self.__createdInstances[name].createCommit(name, val, idx, acInfo) + + self.__createdInstances[name].createCommit(varBind, **context) + # ...commit new column instance - self._vars[name], self.__createdInstances[name] = \ - self.__createdInstances[name], self._vars.get(name) + self._vars[name], self.__createdInstances[name] = self.__createdInstances[name], self._vars.get(name) + + def createCleanup(self, varBind, **context): + name, val = varBind - def createCleanup(self, name, val, idx, acInfo): # Drop previous column instance self.branchVersionId += 1 if name in self.__createdInstances: if self.__createdInstances[name] is not None: - self.__createdInstances[name].createCleanup(name, val, idx, - acInfo) + self.__createdInstances[name].createCleanup(varBind, **context) del self.__createdInstances[name] + elif name in self._vars: - self._vars[name].createCleanup(name, val, idx, acInfo) + self._vars[name].createCleanup(varBind, **context) + + def createUndo(self, varBind, **context): + name, val = varBind - def createUndo(self, name, val, idx, acInfo): # Set back previous column instance, drop the new one if name in self.__createdInstances: self._vars[name] = self.__createdInstances[name] @@ -890,60 +990,77 @@ class MibTableColumn(MibScalar): # Remove new instance on rollback if self._vars[name] is None: del self._vars[name] + else: # Catch half-created instances (hackerish) try: self._vars[name] == 0 + except PyAsn1Error: del self._vars[name] + else: - self._vars[name].createUndo(name, val, idx, acInfo) + self._vars[name].createUndo(varBind, **context) # Column destruction - def destroyTest(self, name, val, idx, acInfo): - (acFun, acCtx) = acInfo + def destroyTest(self, varBind, **context): + name, val = varBind + # Make sure destruction is allowed if name == self.name: - raise error.NoAccessError(idx=idx, name=name) + raise error.NoAccessError(name=name, idx=context.get('idx')) + if name not in self._vars: return + + acFun = context.get('acFun') if acFun: - if val is not None and self.maxAccess != 'readcreate' or \ - acFun(name, self.syntax, idx, 'write', acCtx): - raise error.NoAccessError(idx=idx, name=name) - self._vars[name].destroyTest(name, val, idx, acInfo) + if (val is not None and self.maxAccess != 'readcreate' or + acFun('write', (name, self.syntax), **context)): + raise error.NoAccessError(name=name, idx=context.get('idx')) + + self._vars[name].destroyTest(varBind, **context) + + def destroyCommit(self, varBind, **context): + name, val = varBind - def destroyCommit(self, name, val, idx, acInfo): # Make a copy of column instance and take it off the tree if name in self._vars: - self._vars[name].destroyCommit(name, val, idx, acInfo) + self._vars[name].destroyCommit(varBind, **context) self.__destroyedInstances[name] = self._vars[name] del self._vars[name] - def destroyCleanup(self, name, val, idx, acInfo): + def destroyCleanup(self, varBind, **context): + name, val = varBind + # Drop instance copy self.branchVersionId += 1 + if name in self.__destroyedInstances: - self.__destroyedInstances[name].destroyCleanup(name, val, - idx, acInfo) + self.__destroyedInstances[name].destroyCleanup(varBind, **context) debug.logger & debug.flagIns and debug.logger('destroyCleanup: %s=%r' % (name, val)) del self.__destroyedInstances[name] - def destroyUndo(self, name, val, idx, acInfo): + def destroyUndo(self, varBind, **context): + name, val = varBind + # Set back column instance if name in self.__destroyedInstances: self._vars[name] = self.__destroyedInstances[name] - self._vars[name].destroyUndo(name, val, idx, acInfo) + self._vars[name].destroyUndo(varBind, **context) del self.__destroyedInstances[name] # Set/modify column - def writeTest(self, name, val, idx, acInfo): + def writeTest(self, varBind, **context): + name, val = varBind + # Besides common checks, request row creation on no-instance try: # First try the instance - MibScalar.writeTest(self, name, val, idx, acInfo) + MibScalar.writeTest(self, varBind, **context) + # ...otherwise proceed with creating new column except (error.NoSuchInstanceError, error.RowCreationWanted): excValue = sys.exc_info()[1] @@ -951,42 +1068,60 @@ class MibTableColumn(MibScalar): self.__rowOpWanted[name] = excValue else: self.__rowOpWanted[name] = error.RowCreationWanted() - self.createTest(name, val, idx, acInfo) + self.createTest(varBind, **context) + except error.RowDestructionWanted: self.__rowOpWanted[name] = error.RowDestructionWanted() - self.destroyTest(name, val, idx, acInfo) + self.destroyTest(varBind, **context) + if name in self.__rowOpWanted: debug.logger & debug.flagIns and debug.logger( '%s flagged by %s=%r, exception %s' % (self.__rowOpWanted[name], name, val, sys.exc_info()[1])) raise self.__rowOpWanted[name] - def __delegateWrite(self, subAction, name, val, idx, acInfo): + def __delegateWrite(self, subAction, varBind, **context): + name, val = varBind + if name not in self.__rowOpWanted: - getattr(MibScalar, 'write' + subAction)(self, name, val, idx, acInfo) - return + actionFun = getattr(MibScalar, 'write' + subAction) + return actionFun(self, varBind, **context) + if isinstance(self.__rowOpWanted[name], error.RowCreationWanted): - getattr(self, 'create' + subAction)(name, val, idx, acInfo) + actionFun = getattr(self, 'create' + subAction) + return actionFun(varBind, **context) + if isinstance(self.__rowOpWanted[name], error.RowDestructionWanted): - getattr(self, 'destroy' + subAction)(name, val, idx, acInfo) + actionFun = getattr(self, 'destroy' + subAction) + return actionFun(varBind, **context) - def writeCommit(self, name, val, idx, acInfo): - self.__delegateWrite('Commit', name, val, idx, acInfo) + def writeCommit(self, varBind, **context): + name, val = varBind + + self.__delegateWrite('Commit', varBind, **context) if name in self.__rowOpWanted: raise self.__rowOpWanted[name] - def writeCleanup(self, name, val, idx, acInfo): + def writeCleanup(self, varBind, **context): + name, val = varBind + self.branchVersionId += 1 - self.__delegateWrite('Cleanup', name, val, idx, acInfo) + + self.__delegateWrite('Cleanup', varBind, **context) + if name in self.__rowOpWanted: e = self.__rowOpWanted[name] del self.__rowOpWanted[name] debug.logger & debug.flagIns and debug.logger('%s dropped by %s=%r' % (e, name, val)) raise e - def writeUndo(self, name, val, idx, acInfo): + def writeUndo(self, varBind, **context): + name, val = varBind + if name in self.__rowOpWanted: self.__rowOpWanted[name] = error.RowDestructionWanted() - self.__delegateWrite('Undo', name, val, idx, acInfo) + + self.__delegateWrite('Undo', varBind, **context) + if name in self.__rowOpWanted: e = self.__rowOpWanted[name] del self.__rowOpWanted[name] @@ -1075,7 +1210,9 @@ class MibTableRow(MibTree): # Fate sharing mechanics - def announceManagementEvent(self, action, name, val, idx, acInfo): + def announceManagementEvent(self, action, varBind, **context): + name, val = varBind + # Convert OID suffix into index vals instId = name[len(self.name) + 1:] baseIndices = [] @@ -1096,14 +1233,14 @@ class MibTableRow(MibTree): if not baseIndices: return - for modName, mibSym in self.augmentingRows.keys(): + for modName, mibSym in self.augmentingRows: mibObj, = mibBuilder.importSymbols(modName, mibSym) debug.logger & debug.flagIns and debug.logger('announceManagementEvent %s to %s' % (action, mibObj)) - mibObj.receiveManagementEvent( - action, baseIndices, val, idx, acInfo - ) + mibObj.receiveManagementEvent(action, (baseIndices, val), **context) + + def receiveManagementEvent(self, action, varBind, **context): + baseIndices, val = varBind - def receiveManagementEvent(self, action, baseIndices, val, idx, acInfo): # The default implementation supports one-to-one rows dependency newSuffix = () # Resolve indices intersection @@ -1118,7 +1255,7 @@ class MibTableRow(MibTree): if newSuffix: debug.logger & debug.flagIns and debug.logger( 'receiveManagementEvent %s for suffix %s' % (action, newSuffix)) - self.__manageColumns(action, (), newSuffix, val, idx, acInfo) + self.__manageColumns(action, (), (newSuffix, val), **context) def registerAugmentions(self, *names): for modName, symName in names: @@ -1137,8 +1274,9 @@ class MibTableRow(MibTree): def getIndexNames(self): return self.indexNames - def __manageColumns(self, action, excludeName, nameSuffix, - val, idx, acInfo): + def __manageColumns(self, action, excludeName, varBind, **context): + nameSuffix, val = varBind + # Build a map of index names and values for automatic initialization indexVals = {} instId = nameSuffix @@ -1154,65 +1292,71 @@ class MibTableRow(MibTree): if name == excludeName: continue + actionFun = getattr(var, action) + if name in indexVals: - getattr(var, action)(name + nameSuffix, indexVals[name], idx, - (None, None)) + # NOTE(etingof): disable VACM call + _context = context.copy() + _context.pop('acFun', None) + + actionFun((name + nameSuffix, indexVals[name]), **_context) else: - getattr(var, action)(name + nameSuffix, val, idx, acInfo) + actionFun((name + nameSuffix, val), **context) debug.logger & debug.flagIns and debug.logger('__manageColumns: action %s name %s suffix %s %svalue %r' % ( action, name, nameSuffix, name in indexVals and "index " or "", indexVals.get(name, val))) - def __delegate(self, subAction, name, val, idx, acInfo): + def __delegate(self, subAction, varBind, **context): + name, val = varBind + # Relay operation request to column, expect row operation request. rowIsActive = False + try: - getattr(self.getBranch(name, idx), 'write' + subAction)( - name, val, idx, acInfo - ) + writeFun = getattr(self.getBranch(name, **context), 'write' + subAction) + writeFun(varBind, **context) except error.RowCreationWanted: + createAction = 'create' + subAction + self.__manageColumns( - 'create' + subAction, name[:len(self.name) + 1], - name[len(self.name) + 1:], None, idx, acInfo + createAction, name[:len(self.name) + 1], (name[len(self.name) + 1:], None), **context ) - self.announceManagementEvent( - 'create' + subAction, name, None, idx, acInfo - ) + self.announceManagementEvent(createAction, (name, None), **context) # watch for RowStatus == 'stActive' rowIsActive = sys.exc_info()[1].get('syntax', 0) == 1 except error.RowDestructionWanted: + destroyAction = 'destroy' + subAction + self.__manageColumns( - 'destroy' + subAction, name[:len(self.name) + 1], - name[len(self.name) + 1:], None, idx, acInfo + destroyAction, name[:len(self.name) + 1], (name[len(self.name) + 1:], None), **context ) - self.announceManagementEvent( - 'destroy' + subAction, name, None, idx, acInfo - ) + self.announceManagementEvent(destroyAction, (name, None), **context) return rowIsActive - def writeTest(self, name, val, idx, acInfo): - self.__delegate('Test', name, val, idx, acInfo) + def writeTest(self, varBind, **context): + self.__delegate('Test', varBind, **context) - def writeCommit(self, name, val, idx, acInfo): - rowIsActive = self.__delegate('Commit', name, val, idx, acInfo) + def writeCommit(self, varBind, **context): + name, val = varBind + rowIsActive = self.__delegate('Commit', varBind, **context) if rowIsActive: for mibNode in self._vars.values(): - colNode = mibNode.getNode(mibNode.name + name[len(self.name) + 1:]) + colNode = mibNode.getNode(mibNode.name + name[len(self.name) + 1:], **context) if not colNode.syntax.hasValue(): raise error.InconsistentValueError(msg='Row consistency check failed for %r' % colNode) - def writeCleanup(self, name, val, idx, acInfo): + def writeCleanup(self, varBind, **context): self.branchVersionId += 1 - self.__delegate('Cleanup', name, val, idx, acInfo) + self.__delegate('Cleanup', varBind, **context) - def writeUndo(self, name, val, idx, acInfo): - self.__delegate('Undo', name, val, idx, acInfo) + def writeUndo(self, varBind, **context): + self.__delegate('Undo', varBind, **context) # Table row management |