¿Cómo se puede obtener el código de retorno SSH usando Paramiko?

97
client = paramiko.SSHClient()
stdin, stdout, stderr = client.exec_command(command)

¿Hay alguna forma de obtener el código de retorno del comando?

Es difícil analizar todos los stdout / stderr y saber si el comando finalizó correctamente o no.

Beyonder
fuente

Respuestas:

51

SSHClient es una clase contenedora simple alrededor de la funcionalidad de nivel más bajo en Paramiko. La documentación de la API enumera un método recv_exit_status () en la clase Channel.

Un guión de demostración muy simple:

$ cat sshtest.py
import paramiko
import getpass

pw = getpass.getpass()

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect('127.0.0.1', password=pw)

while True:
    cmd = raw_input("Command to run: ")
    if cmd == "":
        break
    chan = client.get_transport().open_session()
    print "running '%s'" % cmd
    chan.exec_command(cmd)
    print "exit status: %s" % chan.recv_exit_status()

client.close()

$ python sshtest.py
Password: 
Command to run: true
running 'true'
exit status: 0
Command to run: false
running 'false'
exit status: 1
Command to run: 
$
JanC
fuente
Realmente agradezco tu respuesta !! Lo he usado en mi proyecto. Muchas gracias. Hasta ahora puedo usar paramiko en lugar de ajustar el comando del sistema ssh en la programación con python.
Beyonder
Es solo algo que armé al mirar la fuente de SSHClient, por lo que puede que no sea óptimo . Por cierto: si esto hace lo que quieres, es posible que desees "aceptar" mi respuesta.
JanC
Link Dead Please Update
bhathiya-perera
3
chan.recv_exit_status () - encantador cuando esto simplemente se cuelga y nunca regresa. Buen consejo.
aaa90210
9
Ésta es una mala solución. Vea la respuesta de @apdastous a continuación, es mucho mejor.
Patrick
282

Un ejemplo mucho más fácil que no implica invocar directamente la clase de canal de "nivel inferior" (es decir, NO usar el client.get_transport().open_session()comando):

import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('blahblah.com')

stdin, stdout, stderr = client.exec_command("uptime")
print stdout.channel.recv_exit_status()    # status is 0

stdin, stdout, stderr = client.exec_command("oauwhduawhd")
print stdout.channel.recv_exit_status()    # status is 127
apdastous
fuente
5
Lo bueno de este ejemplo es capturar no solo EXIT (como se pregunta en la pregunta), sino demostrar que aún puede obtener STDOUT y STDERR. Hace años, fui engañado por la base de código de ejemplo anémica de Paramiko (sin faltarle el respeto), y para obtener EXIT recurrí a llamadas de transporte () de bajo nivel. transport () parecía forzarte a "elegir uno" (lo cual puede no ser cierto, pero la falta de ejemplos y documentos tutoriales me llevó a creer eso) ...
Scott Prive
Si bien está en lo correcto recv_exit_status, no puede usarlo de esta manera, ya que el código puede bloquearse. Tienes que consumir la salida del comando, mientras esperas a que termine el comando. Vea Paramiko ssh morir / colgar con gran salida .
Martin Prikryl hace
5

Gracias por JanC, agregué algunas modificaciones para el ejemplo y lo probé en Python3, fue realmente útil para mí.

import paramiko
import getpass

pw = getpass.getpass()

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
#client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def start():
    try :
        client.connect('127.0.0.1', port=22, username='ubuntu', password=pw)
        return True
    except Exception as e:
        #client.close()
        print(e)
        return False

while start():
    key = True
    cmd = input("Command to run: ")
    if cmd == "":
        break
    chan = client.get_transport().open_session()
    print("running '%s'" % cmd)
    chan.exec_command(cmd)
    while key:
        if chan.recv_ready():
            print("recv:\n%s" % chan.recv(4096).decode('ascii'))
        if chan.recv_stderr_ready():
            print("error:\n%s" % chan.recv_stderr(4096).decode('ascii'))
        if chan.exit_status_ready():
            print("exit status: %s" % chan.recv_exit_status())
            key = False
            client.close()
client.close()
semilla de perilla
fuente
¿Recibimos algún mensaje de error, si lo hay, en chan.recv_stderr_ready () ?. ¿Chan.recv_stderr (4096) .decode ('ascii') devuelve un mensaje de texto?
kten
0

En mi caso, el búfer de salida fue el problema. Debido al almacenamiento en búfer, las salidas de la aplicación no salen sin bloqueo. Puede encontrar la respuesta sobre cómo imprimir la salida sin almacenar en búfer aquí: Desactive el almacenamiento en búfer de salida . Para abreviar, simplemente ejecute python con la opción -u como esta:

> python -u script.py

Youngmin Kim
fuente