I have a wrapper around Paramiko's SSHClient.exec_command()
. I'd like to capture standard out. Here's a shortened version of my function:
def __execute(self, args, sudo=False, capture_stdout=True, plumb_stderr=True,
ignore_returncode=False):
argstr = ' '.join(pipes.quote(arg) for arg in args)
channel = ssh.get_transport().open_session()
channel.exec_command(argstr)
channel.shutdown_write()
# Handle stdout and stderr until the command terminates
captured = []
def do_capture():
while channel.recv_ready():
o = channel.recv(1024)
if capture_stdout:
captured.append(o)
else:
sys.stdout.write(o)
sys.stdout.flush()
while plumb_stderr and channel.recv_stderr_ready():
sys.stderr.write(channel.recv_stderr(1024))
sys.stderr.flush()
while not channel.exit_status_ready():
do_capture()
# We get data after the exit status is available, why?
for i in xrange(100):
do_capture()
rc = channel.recv_exit_status()
if not ignore_returncode and rc != 0:
raise Exception('Got return code %d executing %s' % (rc, args))
if capture_stdout:
return ''.join(captured)
paramiko.SSHClient.execute = __execute
In do_capture()
, whenever channel.recv_ready()
tells me that I can receive data from the command's stdout, I call channel.recv(1024)
and append the data to my buffer. I stop when the command's exit status is available.
However, it seems like more stdout data comes at some point after the exit status.
# We get data after the exit status is available, why?
for i in xrange(100):
do_capture()
I can't just call do_capture()
once, as it seems like channel.recv_ready()
will return False for a few milliseconds, and then True, and more data is received, and then False again.
I'm using Python 2.7.6 with Paramiko 1.15.2.
I encountered the same issue.
This link (Paramiko: how to ensure data is received between commands) gave me some help, in explaining that after you get
exit_status_ready()
you still have to receive possible additional data. In my tests (with a couple of screens of output), in every single run, there will be additional data to read afterexit_status_ready()
returnsTrue
.But the way it reads the remaining data it is not correct: it uses
recv_ready()
to check if there is something to read, and oncerecv_ready()
returns False it exits. Now, it will work most of the time. But the following situation can happen:recv_ready()
can returnFalse
to indicate that at that moment there is nothing to receive, but it doesn't mean that it is the end of the all data. In my tests, I would leave the test running, and sometimes it would take half an hour for the issue to appear.I found the solution by reading the following sentence in the
Channel.recv()
documentation:"If a string of length zero is returned, the channel stream has closed."
So we just can have a single loop and read all the data until
recv()
returns zero length result. At that point channel stream is closed, but just to make sure that exit status is ready we can make additional loop and sleep untilchannel.exit_status_ready()
returnsTrue
.Note that this will work only with a channel without pty enabled (which is default).