I'm using paramiko to collect some information on a remote host and experience issues, when reading (read()
/readline()
/readlines()
) from the stderr
channel.
Sometimes stderr.read()
returns an empty string which to me looks like a result of a race condition.
However, according to documentation and examples I found on the internet, this seems the exact way to go.
I also tried to open a dedicated channel and make use of chan.recv_ready()
/ chan.recv_stderr_ready()
and reading from respective channels in a loop via chan.recv()
/ chan.recv_stderr()
which however results in the same behaviour.
Here's a minimal test case which - in my setup - reliably causes that behaviour.
import paramiko
class SSH:
def __init__(self):
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect('127.0.0.1', port=31337, username='root', password='root')
self.stdout = ''
self.stderr = ''
self.exit_code = 0
def _run_cmd(self, cmd):
self.stdout = ''
self.stderr = ''
stdin, stdout, stderr = self.ssh.exec_command(cmd)
self.stdout = stdout.read()
self.stderr = stderr.read()
while not stdout.channel.exit_status_ready():
pass
self.exit_code = stdout.channel.recv_exit_status()
if self.exit_code:
print("ERROR: " + self.stderr)
def process_list(self):
self._run_cmd('ls /proc/ | grep -E "^[0-9]+$" | grep -v $$')
lines = self.stdout.split('\n')[:-1]
data = []
for process in lines:
process_data = {}
process_data['pid'] = int(process)
# fetching and parsing process status information from /proc/[PID]/status
self._run_cmd('cat /proc/%d/status' % (int(process)))
data.append(self.stdout)
return data
data = SSH()
while True:
print data.process_list()
What I get after a couple of runs (if not the first one already) is:
ERROR:
while I am expecting:
ERROR: cat: /proc/12883/status: No such file or directory
How can I make sure stderr is ready to read from / I read all data on stderr?