18

I am using the below code:

import paramiko

def runSshCmd(hostname, username, password, cmd, timeout=None):          
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(hostname, username=username, password=password,
            allow_agent=False, look_for_keys=False, timeout=timeout) 
    stdin, stdout, stderr = client.exec_command(cmd)
    stdin.flush()
    data = stdout.read()
    print (data)
    client.close()

runSshCmd("10.128.12.32", "root", "C0mput3Gr!d", "ts_menu")

when it comes to stdout.read() , it hangs... sometimes it prints the output after long time.

Can you please suggest if anything can be done about this issue??

I see this issue has been reported in :

https://bugs.python.org/issue24026

Is there any better module in python for ssh connection and run commands ??

Dmitry Tokarev
  • 1,851
  • 15
  • 29
user3378508
  • 209
  • 1
  • 2
  • 8

6 Answers6

20

Could be related to https://github.com/paramiko/paramiko/issues/109

Below is explanation of what i am facing and how i worked around it.

I also experienced this issue it is due to stdout.channel.eof_received == 0

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("1.1.1.1", username="root", password="pass")
stdin, stdout, stderr = client.exec_command("service XXX start")

stdin, stdout and stderr are staying open...

>>> print stdin
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stdout
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stderr
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>

So EOF was not received...

>>> print stdin.channel.eof_received
0

Usually I receive True and can just stdout.read(), but to be safe i use this workaround (which works!): Wait for a timeout, force stdout.channel.close() and then stdout.read():

>>> timeout = 30
>>> import time
>>> endtime = time.time() + timeout
>>> while not stdout.channel.eof_received:
...     sleep(1)
...     if time.time() > endtime:
...         stdout.channel.close()
...         break
>>> stdout.read()
'Starting XXX: \n[  OK  ]\rProgram started . . .\n'
>>>

BTW i use:

Python 2.6.6
paramiko (1.15.2)

Hope this helps...

Dmitry Tokarev
  • 1,851
  • 15
  • 29
  • 1
    Where did you put your workaround? Since `client.exec_command` never returns, presumably it has to be in the internals of paramiko? – Steve Lorimer Mar 26 '20 at 23:05
  • @SteveLorimer for me and the person who posted this question `client.exec_command()` returned. Our code was hanging on `stdout.read()` – Dmitry Tokarev Jun 03 '20 at 03:12
6

I happen to come across this issue. But I kinda work around it by using "readline" instead "readlines".

For example:

client = paramiko.SSHClient()
client.connect(addr, port, username, password)
stdin, stdout, stderr = client.exec_command(cmd)

while True:
    print(stdout.readline())
    if stdout.channel.exit_status_ready():
        break

So it will print every line immediately and no more hanging, also exit_status_ready() will make sure the loop breaks when stdout has stopped/exited.

Carl Cheung
  • 498
  • 5
  • 8
3

It use to happen when there is no data in stdout or there is a line without eol (i.e. in a read statement inside a sh script). Try setting 'get_pty=True', then reading only the bytes in stdout. To avoid infinite loops, it'd be a good idea setting a timeout and a sleep in spite of the continue statement:

stdin, stdout, stderr = ssh.exec_command("your-command",get_pty=True)
stdout.flush()
nbytes = 0
while (len(stdout.channel.in_buffer)==0):
     continue

nbytes=len(stdout.channel.in_buffer)
print(nbytes)
stdout.read(nbytes)
nachopol
  • 43
  • 5
2

try to close stdin before you use stdout.

env:
python3.8
paramiko-2.7.2

stdin, stdout, stderr = client.exec_command(cmd)
stdin.close()
for line in iter(stout.readline,""):
    print(line, end='')
J. M. Arnold
  • 6,261
  • 3
  • 20
  • 38
-1

For anyone still struggling with this: I was able to fix this by running client.close() before trying to read from stdout or stderr.

Bryan Bugyi
  • 149
  • 5
  • making a new client for every single command seems unnecessary – dmbhatti Oct 29 '20 at 13:02
  • @dmbhatti True. It is a valid work-around though. I don't believe the most-voted answer works on the version of paramiko we are running. Not sure though. It's been a while. – Bryan Bugyi Nov 18 '20 at 01:14
-1

If you are expecting a specific output when your command is done you can remove data = stdout.read() and write this

        while True:
            if "Ended" in str(stdout.readline()):
                stdout.channel.close()
                break

In my case my command would return something that has "Ended" so i'd check for it and if yes then execute stdout.channel.close() this fixed my problem. In your case "Ended" can be anything that you're expecting to get