Greetings,<br><br>I have a problem I hope someone here can assist with. I&#39;m using TwistedSNMP to query a bunch of SNMP devices asynchronously. The behavior I&#39;m trying to get is to get is to query all the devices via SNMP, each query returns a deferred, and when all their callbacks have been fired then I want to stop the reactor and thereby exit the program. I thought perhaps I could put each of these SNMP deferreds in a DeferredList and add a callback to the DeferredList that would stop the reactor but it does not do that. Enclosed is a code sample. Am I doing something incorrectly, or should I do something different?<br>
<br>Thanks! -Don<br><br>&quot;&quot;&quot;Trivial example to retrieve an OID from a remote Agent&quot;&quot;&quot;<br>from twisted.internet import reactor<br>from twistedsnmp import snmpprotocol, agentproxy<br>from twisted.enterprise import adbapi<br>
from twisted.internet import defer<br>import os<br><br>APPNAME = &#39;ClearSNMP&#39;<br>d_results = {} #dictionary to store results<br>device_name = &#39;Unknown&#39;<br><br>db_conn = {&#39;user&#39;:&#39;sa&#39;,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;password&#39;:&#39;password&#39;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;host&#39;:&#39;localhost&#39;,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;database&#39;:&#39;ClearSNMP&#39;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>community_string = &#39;public&#39;<br><br>deferred_list = [] #list to help group the snmp requests<br>
<br>outfile = open(&#39;outfile.csv&#39;,&#39;wb&#39;,0)<br>#add headers to the outfile<br>outfile.write(&quot;device_name,link_oid,link_name,link_capacity_oid,link_capacity,traffic_in_oid,traffic_in,traffic_out_oid,traffic_out&quot;)<br>
<br>#create the database connection pool<br>dbpool = adbapi.ConnectionPool(&quot;pymssql&quot;, user=db_conn[&#39;user&#39;], password=db_conn[&#39;password&#39;], host=db_conn[&#39;host&#39;], database=db_conn[&#39;database&#39;])<br>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>def main( class_handler, proxy, oids ):<br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;Do a getTable on proxy for OIDs and store in oidStore&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp; df = proxy.getTable(<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; oids, timeout=.25, retryCount=5<br>
&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; if class_handler == &#39;tasman&#39;:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; df.addCallback( tasmanResults )<br>&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; df.addCallback( results )<br>&nbsp;&nbsp;&nbsp; #df.addCallback( exiter )<br>&nbsp;&nbsp;&nbsp; df.addErrback( errorReporter, proxy )<br>
&nbsp;&nbsp;&nbsp; #df.addErrback( exiter )<br>&nbsp;&nbsp;&nbsp; return df<br><br><br>def tasmanResults( result ):<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;Results &#39;appear&#39; to be a nested dictionary, but it is really an object of OIDs. I figured out how to get to the OIDs by<br>
&nbsp;&nbsp;&nbsp; casting them as a dictionary using the built_in dict() function. Now I can iterate over all the OIDs.&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp; #print &#39;Results:&#39;<br>&nbsp;&nbsp;&nbsp; d_table_key = {}<br>&nbsp;&nbsp;&nbsp; for table_key in result.keys():&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #get the device name. for some reason i have to do this in a loop as just saying dict(result[table_key])[&#39;.1.3.6.1.2.1.1.5.0&#39;] doesn&#39;t work<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for oid in dict(result[table_key]).keys():&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if oid==&#39;.1.3.6.1.2.1.1.5.0&#39;:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; device_name=str(dict(result[table_key])[oid])<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_oid = {}<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for oid in dict(result[table_key]).keys():&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_oid[str(oid)]=dict(result[table_key])[oid]<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_table_key[str(table_key)] = d_oid<br>&nbsp;&nbsp;&nbsp; d_results[device_name]=d_table_key<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; #specify the table oids so we can match them appropriately later<br>
&nbsp;&nbsp;&nbsp; link_name_table&nbsp;&nbsp;&nbsp; = &quot;.1.3.6.1.2.1.2.2.1.2&quot;<br>&nbsp;&nbsp;&nbsp; link_capacity_table&nbsp;&nbsp;&nbsp; = &quot;.1.3.6.1.2.1.2.2.1.5&quot;<br>&nbsp;&nbsp;&nbsp; traffic_in_table&nbsp;&nbsp;&nbsp; = &quot;.1.3.6.1.2.1.2.2.1.10&quot;<br>&nbsp;&nbsp;&nbsp; traffic_out_table&nbsp;&nbsp;&nbsp; = &quot;.1.3.6.1.2.1.2.2.1.16&quot;<br>
<br>&nbsp;&nbsp;&nbsp; # For each link name in the table I need to get the values from the link_capacity, traffic_in and traffic_out tables and put them in the same line<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; for i in d_results.keys():<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row = {} #holds the column values for a row<br>
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #set device_name in Row<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;device_name&#39;] = device_name<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for k in d_results[i][link_name_table]:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #set link_oid and link_name in Row<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;link_oid&#39;] = k<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;link_name&#39;] = d_results[i][link_name_table][d_row[&#39;link_oid&#39;]]<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #lookup the capacity metric for this link_oid<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #create the oid to lookup<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;link_capacity_oid&#39;] = d_row[&#39;link_oid&#39;].replace(link_name_table,link_capacity_table)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;link_capacity&#39;] = d_results[i][link_capacity_table][d_row[&#39;link_capacity_oid&#39;]]<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #lookup the traffic_in metric for this link_oid<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #create the oid to lookup<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;traffic_in_oid&#39;] = d_row[&#39;link_oid&#39;].replace(link_name_table,traffic_in_table)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;traffic_in&#39;] = d_results[i][traffic_in_table][d_row[&#39;traffic_in_oid&#39;]]<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #lookup the traffic_out metric for this link_oid<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #create the oid to lookup<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;traffic_out_oid&#39;] = d_row[&#39;link_oid&#39;].replace(link_name_table,traffic_out_table)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_row[&#39;traffic_out&#39;] = d_results[i][traffic_out_table][d_row[&#39;traffic_out_oid&#39;]]<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #Calculate Utilization - if we can<br><br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #print d_row<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; out = d_row[&#39;device_name&#39;]+&quot;,&quot;+d_row[&#39;link_oid&#39;]+&quot;,&quot;+d_row[&#39;link_name&#39;]+&quot;,&quot;+d_row[&#39;link_capacity_oid&#39;]+&quot;,&quot;+str(d_row[&#39;link_capacity&#39;])+&quot;,&quot;+d_row[&#39;traffic_in_oid&#39;]+&quot;,&quot;+str(d_row[&#39;traffic_in&#39;])+&quot;,&quot;+d_row[&#39;traffic_out_oid&#39;]+&quot;,&quot;+str(d_row[&#39;traffic_out&#39;])+&#39;\r\n&#39;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #print out<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; outfile.write(out)<br>&nbsp;&nbsp;&nbsp; return result<br><br><br>def errorReporter( err, proxy ):<br>&nbsp;&nbsp;&nbsp; #print &#39;ERROR&#39;, err.getTraceback()<br>&nbsp;&nbsp;&nbsp; #log the failed snmp query attempt<br>&nbsp;&nbsp;&nbsp; print &#39;Failed to retrieve SNMP counters from agent:&#39;,proxy<br>
&nbsp;&nbsp;&nbsp; return err<br><br>def exiter( value ):<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; reactor.stop()<br>&nbsp;&nbsp;&nbsp; outfile.close()<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; return value<br><br><br>def getNetworkElements():<br>&nbsp;&nbsp;&nbsp; return dbpool.runQuery(&quot;select top 10 ip, mkt, dns_name, dns_fqdn from dns where dns_type=&#39;TASMAN&#39;&quot;)<br>
<br>def printResult(l):<br>&nbsp;&nbsp;&nbsp; for item in l:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;Fetching counters for &quot;+item[2]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #deferred_list.append(snmpSetup(item[0], 161, &#39;ctipublic&#39;,&#39;tasman&#39;))<br>&nbsp;&nbsp;&nbsp; ipAddress = item[0]<br>
&nbsp;&nbsp;&nbsp; portno = 161<br>&nbsp;&nbsp;&nbsp; community = community_string<br>&nbsp;&nbsp;&nbsp; class_handler = &#39;tasman&#39;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print ipAddress,portno<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # choose random port in range 25000 to 30000<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; port = snmpprotocol.port()<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetPort = int(portno)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy = agentproxy.AgentProxy(ipAddress, <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; targetPort, <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; community = community,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; snmpVersion = &#39;v1&#39;,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; protocol = port.protocol,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; )<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d_oids = {&#39;.1.3.6.1.2.1.1&#39;:&quot;System Tables&quot;,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &#39;.1.3.6.1.2.1.2.2.1.2&#39;:&quot;Circuit Name&quot;,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &#39;.1.3.6.1.2.1.2.2.1.5&#39;:&quot;Capacity&quot;,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &#39;.1.3.6.1.2.1.2.2.1.10&#39;:&quot;Traffic In&quot;,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &#39;.1.3.6.1.2.1.2.2.1.16&#39;:&quot;Traffic Out&quot;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;Do a getTable on proxy for OIDs and store in oidStore&quot;&quot;&quot;<br>
&nbsp;&nbsp;&nbsp; df = proxy.getTable(<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_oids, timeout=.25, retryCount=5<br>&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; if class_handler == &#39;tasman&#39;:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; df.addCallback( tasmanResults )<br>&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; df.addCallback( results )<br>&nbsp;&nbsp;&nbsp; df.addErrback( errorReporter, proxy )<br>
&nbsp;&nbsp;&nbsp; deferred_list.append(df)<br>&nbsp;&nbsp;&nbsp; return <br><br><br><br>if __name__ == &quot;__main__&quot;:<br>&nbsp;&nbsp;&nbsp; import sys<br>&nbsp;&nbsp;&nbsp; #start the log service<br>&nbsp;&nbsp;&nbsp; from twisted.python import log<br>&nbsp;&nbsp;&nbsp; from twisted.python import logfile<br>
&nbsp;&nbsp;&nbsp; # rotate every 100000000 bytes<br>&nbsp;&nbsp;&nbsp; f = logfile.LogFile(APPNAME+str(os.getpid())+&quot;.log&quot;, &quot;Logs&quot;, rotateLength=100000000)<br>&nbsp;&nbsp;&nbsp; # setup logging to use our new logfile<br>&nbsp;&nbsp;&nbsp; #log.startLogging(f)<br>
<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; g = getNetworkElements().addCallback(printResult)<br>&nbsp;&nbsp;&nbsp; dl = defer.DeferredList(deferred_list, 0, 0, 1 )<br>&nbsp;&nbsp;&nbsp; print dir(dl)<br>&nbsp;&nbsp;&nbsp; dl.addCallback(exiter)<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; reactor.run()<br>