Re: [pysnmp-users] CLI interaction?
Brought to you by:
elie
From: Ilya E. <il...@gl...> - 2015-12-12 15:39:32
|
Hi Michael, That should be possible, however there is no specialized API for such things in pysnmp. I can advise listening on the __add__() method of SNMP counters objects and fire traps when an increment is detected. SNMP engine maintains a large collection of counters, each has specific meaning and they all are specified in SNMP RFCs. You should be looking for those counters in RFC2576 (SNMP communities) and RFC3414 (USM). Off the top of my head, you may be interested in SNMPv2-MIB::snmpInBadCommunityNames SNMP-USER-BASED-SM-MIB::usmStatsWrongDigests SNMP-USER-BASED-SM-MIB::usmStatsDecryptionErrors SNMP-USER-BASED-SM-MIB::usmStatsUnsupportedSecLevels SNMP-USER-BASED-SM-MIB::usmStatsUnknownUserNames To “listen” for increment event you could monkey parch __add__() method or subclass original class and replace original counter object with your implementation. Here’s a quick prototype: —— from pysnmp.smi import builder from pysnmp.proto.rfc1902 import Counter32 # Use snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder to get hold on SNMP engine’s MIB tree mibBuilder = builder.MibBuilder() class MyCounter32(Counter32): def __add__(self, value): print('sending auth trap') return Counter32.__add__(self, value) snmpInBadCommunityNames, = mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInBadCommunityNames') snmpInBadCommunityNames.syntax = MyCounter32(0) print(snmpInBadCommunityNames.syntax) # this is what SNMP engine does internally snmpInBadCommunityNames.syntax += 1 print(snmpInBadCommunityNames.syntax) # this is what SNMP engine does internally snmpInBadCommunityNames.syntax += 1 print(snmpInBadCommunityNames.syntax) —— Make sure to use the latest pysnmp (4.3.2 from CVS) to make sure the counters are incremented via +=. Sending traps should be easy, just make sure to reuse SnmpEngine object. No need to call stuff like runDispatcher() to push trap out, that would be done automatically by the main loop once trap message is queued. Alternatively to sending traps, you can snmpwalk your running SNMP agent to read all these counters via SNMP and note increments. > On 09 Dec 2015, at 18:20, Michael R Anderson <mic...@gm...> wrote: > > Hi Ilya, > I'm past all the previous problems with you help. > I need to send a Authentication Failure trap if an snmp request passes > incorrect credentials (such as v2 community, or v3 community, user, > md5, des). Can pysnmp be configured to send the trap automatically on > auth failure? > > If not, can I supply it with a call-back to be used if there is a auth > failure so I can send the trap myself? > > Thanks. > > -Mike > > On Wed, Nov 18, 2015 at 2:11 PM, Ilya Etingof <il...@gl...> wrote: >> >> Hi Michael, >> >> From the code snippet you sent, it’s hard to figure out what exactly is the problem. Also ‘thread’ module is somewhat low-level… >> >> I’ve run a quick test with pysnmp 4.3.1 and the 'threading’ module having three independent SNMP engines (managers) running in three threads plus one raw_input() loop in the other. >> >> So it seems to work alright (see attached). >> >> -ilya >> >> >>> On 16 Nov 2015, at 21:41, Michael R Anderson <mic...@gm...> wrote: >>> >>> Hi Ilya, >>> Yes, the snmp part is already in it's own thread. >>> >>> def snmp_thread(self): >>> self.snmp_server_running = True >>> logging.getLogger(__name__).info("xfsnmp:snmp_thread: snmp >>> thread started") >>> self.snmpEngine.transportDispatcher.runDispatcher() # will run >>> forever until jobFinished. >>> logging.getLogger(__name__).info("xfsnmp:snmp_thread: 1") >>> self.snmpEngine.transportDispatcher.closeDispatcher() >>> logging.getLogger(__name__).info("xfsnmp:snmp_thread: 2") >>> self.snmp_server_running = False >>> logging.getLogger(__name__).info("xfsnmp:snmp_thread: 3") >>> sys.stdout.flush();sys.stderr.flush() >>> >>> def start_snmp_server(self): >>> # use specific flags or 'all' for full debugging >>> debug.setLogger(debug.Debug('all')) >>> logging.getLogger(__name__).info("xfsnmp:start_snmp_server: >>> starting snmp server") >>> logging.getLogger(__name__).info("xfsnmp:start_snmp_server: 0") >>> print "sock map", self.snmpEngine.transportDispatcher.getSocketMap() >>> #mySockMap = {} >>> #self.snmpEngine.transportDispatcher.setSocketMap(mySockMap) >>> # register a job - this will keep the dispatcher running until >>> it is unregistered(jobFinished). >>> self.snmpEngine.transportDispatcher.jobStarted(1) >>> logging.getLogger(__name__).info("xfsnmp:start_snmp_server: 1") >>> thread.start_new_thread(self.snmp_thread, ()) >>> logging.getLogger(__name__).info("xfsnmp:start_snmp_server: 2") >>> sys.stdout.flush();sys.stderr.flush() >>> >>> The logging output shows that once runDispatcher() is executed, cly no >>> longer accepts any keyboard input. Until eunDispatcher() cly accepts >>> input and if I comment out only the runDispatcher()/closeDipatcher() >>> lines cly continues to accept input. Having the snmp part in it's own >>> thread doesn't seem to prevent runDispatcher() from stopping cly from >>> accepting input. >>> >>> I'm continuing to look into why this is. Thanks. >>> >>> -Mike >>> >>> >>> >>> On Mon, Nov 16, 2015 at 12:29 PM, Ilya Etingof <il...@gl...> wrote: >>>> Hi Michael, >>>> >>>> SNMP does not touch stdin but blocks on waiting for UDP socket to receive response packet from remove server. In the same time cly blocks waiting on stdin's file descriptor (FD) for your input (yes, raw_input() is blocking by default). Whenever you have a single thread of execution in your program and two blocking calls, you have to execute one or the other at a time. Unless you 1) put one of these calls to a parallel thread of execution or 2) make both blocking calls cooperating thus letting the other one to run while its fellow would block. The first approach is known as a multi-threading design, while the latter is called asynchronous I/O. >>>> >>>> In your case MT might be easier to implement, so I’d try it first. In fact I had an impression that you already did that by putting SNMP part into a dedicated thread (via the threading module). >>>> >>>> Async requires more effort and mind wrapping. The idea is that you switch potentially blocking FDs (sockets) into a non-blocking mode, then pass a collection of them to a dispatcher (select(), poll() etc.) that will watch them for readiness. Once one FD/socket is ready, you could pass it to read()/recvfrom() calls to perform actual I/O. No blocking is done if you do read from FD that has nothing to return - it will indicate that with an error immediately. The only waiting entity with this design is the dispatcher. >>>> >>>> I’ve come across many discussion on the topic: >>>> >>>> https://repolinux.wordpress.com/2012/10/09/non-blocking-read-from-stdin-in-python/ >>>> >>>> Hope this helps, >>>> Ilya >>>> >>>> >>>>> On 15 Nov 2015, at 04:31, Michael R Anderson <mic...@gm...> wrote: >>>>> >>>>> Hi Ilya, >>>>> I didn't mean to say the pysnmp thread blocks the cly thread or vice >>>>> versa. Just that executing rundispather() stopped the command line >>>>> input from reaching cly. That's all I meant. >>>>> >>>>> Is the problem raw_input blocking I/O? Or is it that only one of cly >>>>> or pysnmp reads all input (stdin and port 161), keeps what the map >>>>> says to recognize, ignores the rest, and starves the other of it's >>>>> input? Or did I misunderstand? If that is correct, then if I combine >>>>> the input map from cly with that for pysnmp, either using cly to drive >>>>> or snmp to drive, then somehow I have to get the input (from >>>>> stdin/port 161) from whichever read it to the other. >>>>> >>>>> Is that about right? Any better alternative. >>>>> >>>>> Thanks, >>>>> -Mike >>>>> >>>>> On Sat, Nov 14, 2015 at 12:14 PM, Ilya Etingof <il...@gl...> wrote: >>>>>> >>>>>> The first thing I do not quite understand is why your SNMP call blocks >>>>>> (?) your cly app if your (blocking) pysnmp code runs in a dedicated >>>>>> thread. Can you please elaborate on that point? >>>>>> >>>>>> Alternatively, as Craig says, you may try to switch your stdin file >>>>>> descriptor into non-blocking mode and serve both FD's (SNMP and stdin) >>>>>> by a single select() within a main loop. >>>>>> >>>>>> To start with the second approach, I'd investigate the way how to extent >>>>>> ply input driver to run non-blocking and being managed by a select(). >>>>>> I've looked at the ply code: >>>>>> >>>>>> https://github.com/alecthomas/cly/blob/master/cly/interactive.py >>>>>> >>>>>> so ReadlineDriver class is the place that should probably be >>>>>> hacked/extended to replace blocking raw_inpit() with a non-blocking and >>>>>> select()-managed version like discussed here: >>>>>> >>>>>> http://stackoverflow.com/questions/9027311/how-to-make-non-blocking-raw-input-when-using-eventlet-monkey-patch-and-why-it >>>>>> >>>>>> Once this is working, I could elaborate on >>>>>> two-FDs-been-managed-by-single-select thing. I will probably try to come >>>>>> up with an example script to make it generally useful. >>>>>> >>>>>> -ilya >>>>>> >>>>>> On 11/12/2015 11:15 AM, Craig Small wrote: >>>>>>> Avtually re-reading your email, its not two sockets its an interactive >>>>>>> terminal and a socket. What you can do is put your stdin socket (well >>>>>>> FD) into the socket map. That way the select() is looking at both your >>>>>>> network SNMP socket/fd and your keyboard stdin >>>>>>> >>>>>>> - Craig >>>>>>> >>>>>>> >>>>>>> On Thu, Nov 12, 2015 at 9:09 PM Craig Small <cs...@en... >>>>>>> <mailto:cs...@en...>> wrote: >>>>>>> >>>>>>> >>>>>>> Get's a bit tricky with sockets floating around. What I had to do >>>>>>> was create a new SNMP engine and dispatcher that used my own >>>>>>> socket_map. The socket_map is important because this is what the >>>>>>> select() system calls to listen for the sockets. You can have only >>>>>>> one select() >>>>>>> >>>>>>> You then need to run the dispatcher's jobsArePending and >>>>>>> handleTimerTick to keep the the snmp dispatcher happy. >>>>>>> >>>>>>> I then have the the socket running select(), because you have used >>>>>>> YOUR socket_map then pysnmp has added its socket to the map. >>>>>>> I asked almost the very same thing and Ilya responded here: >>>>>>> >>>>>>> http://sourceforge.net/p/pysnmp/mailman/message/31494830/ >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Thu, Nov 12, 2015 at 11:57 AM Michael R Anderson >>>>>>> <mic...@gm... <mailto:mic...@gm...>> >>>>>>> wrote: >>>>>>> >>>>>>> I am using cly to drive my CLI. It works great. I recently added >>>>>>> pysmp. Now when it gets to runDispatcher() (in it's own thread), it >>>>>>> looks like my CLI input line gets hijacked so that no more command >>>>>>> line input can be done. >>>>>>> >>>>>>> I read runDispacther uses an I/O mainloop somehow. Can this be >>>>>>> causing my CLI is no responsive problem? >>>>>>> >>>>>>> Any suggestions? >>>>>>> >>>>>>> ------------------------------------------------------------------------------ >>>>>>> _______________________________________________ >>>>>>> pysnmp-users mailing list >>>>>>> pys...@li... >>>>>>> <mailto:pys...@li...> >>>>>>> https://lists.sourceforge.net/lists/listinfo/pysnmp-users >>>>>>> >>>>>>> -- >>>>>>> Craig Small (@smallsees) http://enc.com.au/ csmall at : >>>>>>> enc.com.au <http://enc.com.au> >>>>>>> Debian GNU/Linux http://www.debian.org/ csmall at : >>>>>>> debian.org <http://debian.org> >>>>>>> GPG fingerprint: 5D2F B320 B825 D939 04D2 0519 3938 F96B >>>>>>> DF50 FEA5 >>>>>>> >>>>>>> -- >>>>>>> Craig Small (@smallsees) http://enc.com.au/ csmall at : >>>>>>> enc.com.au <http://enc.com.au> >>>>>>> Debian GNU/Linux http://www.debian.org/ csmall at : >>>>>>> debian.org <http://debian.org> >>>>>>> GPG fingerprint: 5D2F B320 B825 D939 04D2 0519 3938 F96B DF50 FEA5 >>>>>>> >>>>>>> >>>>>>> ------------------------------------------------------------------------------ >>>>>>> >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> pysnmp-users mailing list >>>>>>> pys...@li... >>>>>>> https://lists.sourceforge.net/lists/listinfo/pysnmp-users >>>>>>> >>>> >> >> |