For maintanibility purpose and OS portability, I want to change from using netsnmp to pysnmap-lextudio in a python application. Furthermore, since asyncore death is soon, I needed to implement asyncio utilization. I've created a virtual class SnmpManager, and two daughter classes SnmpManagerAsync and SnmpManagerSync to provide synchronous and asynchronous walk and set functionnalities. Depending of a config.ini option, only one daughter class is instancied. Initially, I've created SnmpEngine, UsmUserData, UdpTransportData and ContextData objects in SnmpManager constructor to use them to implement redefined snmp set and walk daughter classes procedures.
But with this solution, when SnmpManagerAsync is instancied (using thus asyncio) the async walk and set procedures are stuck at await setCmd or await nextCmd and the application is blocked.
In order to make it work, I moved the creation of SnmpEngine and UdpTransportData in async procedures as shown below
class SnmpManager:
privProtocol = {
"DES": usmDESPrivProtocol,
"3DES": usm3DESEDEPrivProtocol,
"AES": usmAesCfb128Protocol,
"AES128": usmAesCfb128Protocol,
"AES192": usmAesCfb192Protocol,
"AES192b": usmAesBlumenthalCfb192Protocol,
"AES256": usmAesCfb256Protocol,
"AES256b": usmAesBlumenthalCfb256Protocol,
}
authProtocol = {
"MD5": usmHMACMD5AuthProtocol,
"SHA": usmHMACSHAAuthProtocol,
"SHA224": usmHMAC128SHA224AuthProtocol,
"SHA256": usmHMAC192SHA256AuthProtocol,
"SHA384": usmHMAC256SHA384AuthProtocol,
"SHA512": usmHMAC384SHA512AuthProtocol
}
def __init__(self, config) -> None:
self.host = config['SNMP']['host']
self.port = config['SNMP']['port']
self.user = config['SNMP']['SecName']
self.authProto = config['SNMP']['AuthProto']
self.authKey = config['SNMP']['AuthPass']
self.privProto = config['SNMP']['PrivProto']
self.privKey = config['SNMP']['PrivPass']
self.usm = UsmUserData(userName=config['SNMP']['SecName'],
authKey=self.authKey,
privKey=self.privKey,
authProtocol=self.getAuthProtocol(),
privProtocol=self.getPrivProtocol())
self.contextData = ContextData()
def getAuthProtocol(self):
if self.authProto in self.authProtocol.keys():
auth_protocol = self.authProtocol[self.authProto]
else:
auth_protocol = usmNoAuthProtocol
return auth_protocol
def getPrivProtocol(self):
if self.privProto in self.privProtocol.keys():
priv_protocol = self.privProtocol[self.privProto]
else:
priv_protocol = usmNoPrivProtocol
return priv_protocol
...
...
class SnmpManagerAsync(SnmpManager):
def __init__(self, config) -> None:
super().__init__(config)
# snmp walk
async def async_walk(self, str_oid):
res = []
# workaround ? :(: SnmpEngine and UdpTransportTarget must be created locally within asyncio context utilization
snmp_engine = SnmpEngine()
udp_transport_target = UdpTransportTarget((self.host, self.port))
var_binds = [ObjectType(ObjectIdentity(str_oid))]
while True:
# print(str_oid)
error_indication, error_status, error_index, var_binds_table = await nextCmd(
snmp_engine,
self.usm,
udp_transport_target,
self.contextData,
*var_binds
)
if error_indication:
print(error_indication)
return
elif error_status:
print('%s at %s' % (error_status.prettyPrint(),
error_index and var_binds_table[int(error_index) - 1][0] or '?'))
return
else:
if isEndOfMib(var_binds_table[-1]):
break
else:
for var_bind_row in var_binds_table:
for var_bind in var_bind_row:
oid = '.' + str(var_bind[0])
value = str(var_bind[1])
if oid.startswith(str_oid) is True:
var_bind_ = self.varBind(oid, '', value, None)
res.append(var_bind_)
var_binds = var_binds_table[-1]
return res
# snmp walk
def walk(self, str_oid) -> list:
return asyncio.run(self.async_walk(str_oid))
...
...
class SnmpManagerSync(SnmpManager):
def __init__(self, config) -> None:
super().__init__(config)
self.snmpEngine = SnmpEngine()
self.udpTransportTarget = UdpTransportTarget((self.host, self.port))
# walk
def walk(self, str_oid) -> list:
res = []
try:
iterator = nextCmd(
self.snmpEngine,
self.usm,
self.udpTransportTarget,
self.contextData,
ObjectType(ObjectIdentity(str_oid)),
lexicographicMode=False
)
...
...
Can someone explain to me why I need to move the creation of these two objects SnmpEngine and UdpTransportData in the async procedure body ?