Issue
I am currently building a python script that enables and disables certain ports on switches to see how the switch will act for quality assurance purposes. I've been using a Python library called paramiko which implements SSH to connect to whichever devices I want and I'm referring to legacy code handed by one of my teammates to write more scripts. In one of the legacy code files, there is a function called _run_poll and I'm not understanding what it's doing exactly.
I have tried do some research on what "polling" means in regards to SSH, but I am still not understanding what is going when we are running the "poll". The definition for it seems a little vague. Here is the function:
def _run_poll(self, session, timeout, input_data):
interval = 0.1
maxseconds = timeout
maxcount = maxseconds / interval
i = 0
timeout_flag = False
self.info('polling (%d, %d)' % (maxseconds, maxcount))
start = datetime.datetime.now()
start_secs = time.mktime(start.timetuple())
output = ''
session.setblocking(0)
while True:
if session.recv_ready(): # returns true if data has been buffered
data = session.recv(self.bufsize) # receive data from the channel
output += data
self.info('read %d bytes, total %d' % (len(data), len(output)))
if session.send_ready():
# We received a potential prompt.
# In the future this could be made to work more like
# pexpect with pattern matching.
if i < len(input_data):
data = input_data[input_idx] + '\n'
i += 1
self.info('sending input data %d' % (len(data)))
session.send(data)
self.info('session.exit_status_ready() = %s' % (str(session.exit_status_ready())))
if session.exit_status_ready():
break
# Timeout check
now = datetime.datetime.now()
now_secs = time.mktime(now.timetuple())
et_secs = now_secs - start_secs
self.info('timeout check %d %d' % (et_secs, maxseconds))
if et_secs > maxseconds:
self.info('polling finished - timeout')
timeout_flag = True
break
time.sleep(0.200)
self.info('polling loop ended')
if session.recv_ready():
data = session.recv(self.bufsize)
output += data
self.info('read %d bytes, total %d' % (len(data), len(output)))
self.info('polling finished - %d output bytes' % (len(output)))
if timeout_flag:
self.info('appending timeout message')
output += '\nERROR: timeout after %d seconds\n' % (timeout)
session.close()
return output
I'm not able to find a lot of online resources to describe what is going on here or about "polling" in general. Can anyone help me explain what exactly is "polling" and what is going on here ?
Solution
There are two ways to handle asynchronous events in programming.
One way is to use interrupts: you have code that is not executing until "woken up" by some mechanism, and then it executes. This mechanism must be supported at a lower level than where your code executes. Microcontrollers, for example, have specific hardware built into them which can interrupt the application and jump to a specific address to start executing instructions in order to handle the interrupt.
Building an interrupt system is hard, and takes a significant amount of work. For some applications, it's just not possible. It's nearly always easier (albeit less efficient) to poll, or check a condition repeatedly until it becomes True, then go on to execute something else.
In your example, notice how he uses a while True:
loop. True will never be False, so this while loop can only be broken by a break
statement. We find that break statement at
if session.exit_status_ready():
break
So the writer of that code decided to do something continuously until session.exit_status_ready()
was True. As this is paramiko, it's likely that he executed a remote command over SSH and is waiting until the command finishes and returns an exit code. The point of this loop is to keep the program stuck in the loop until the command has finished executing and returns a result. It also can time out:
if et_secs > maxseconds:
self.info('polling finished - timeout')
timeout_flag = True
break
So if the command takes more than maxseconds
the program won't sit and wait forever.
Once it exits the loop, it prints:
self.info('polling loop ended')
So when you see this message, you know that the remote command finished executing or timed out.
The point of polling is to check something repeatedly until a certain condition occurs. In your case, that condition is a "a remote command has finished executing" or "a certain amount of time has passed."
Answered By - Tom Lubenow