2009-04-17 11 views
21

Voglio eseguire un comando tail -f logfile su una macchina remota usando il modulo paramiko di python. Sto tentando finora nel modo seguente:Comandi ssh di lunga durata nel modulo paramiko python (e come terminarli)

interface = paramiko.SSHClient() 
#snip the connection setup portion 
stdin, stdout, stderr = interface.exec_command("tail -f logfile") 
#snip into threaded loop 
print stdout.readline() 

mi piacerebbe il comando da eseguire tutto il tempo necessario, ma ho 2 problemi:

  1. Come arresto questo pulito? Ho pensato di creare un canale e quindi di utilizzare il comando shutdown() sul canale quando ho finito con esso- ma ciò sembra disordinato. È possibile fare qualcosa come inviato Ctrl-C allo stdin del canale?
  2. readline() blocchi, e potrei evitare i thread se avessi un metodo non bloccante per ottenere output, qualche pensiero?
+0

Odio interrompere la notizia cattiva, ma SSHClient() utilizza già i thread internamente. – joeforker

risposta

14

1) È possibile chiudere il client se lo si desidera. Il server all'altra estremità ucciderà il processo di coda.

2) Se è necessario eseguire questa operazione in modo non bloccante, sarà necessario utilizzare direttamente l'oggetto canale. È quindi possibile guardare sia per stdout sia per stderr con channel.recv_ready() e channel.recv_stderr_ready() oppure utilizzare select.select.

+1

Sono in ritardo per la festa, ma non 'exec_command' stesso che non blocca? – zengr

+1

Hai ragione, ma la domanda si pone su 'readline()'. – Dan

+1

Su alcuni server più recenti, i processi non verranno uccisi anche dopo aver terminato il client. È necessario impostare 'get_pty = True' in' exec_command() 'affinché i processi vengano ripuliti dopo essere usciti dal client. – nlsun

0

Per chiudere il processo sufficiente eseguire:

interface.close() 

In termini di non bloccante, non è possibile ottenere un bloccante leggere. Il meglio che si sarebbe in grado di analizzare è un "blocco" alla volta, "stdout.read (1)" si bloccherà solo quando non ci sono caratteri rimasti nel buffer.

21

Invece di chiamare exec_command sul client, ottenere il trasporto e generare il proprio canale. Il channel può essere utilizzato per eseguire un comando, e si può utilizzare in una dichiarazione prescelta per sapere quando i dati possono essere letti:

#!/usr/bin/env python 
import paramiko 
import select 
client = paramiko.SSHClient() 
client.load_system_host_keys() 
client.connect('host.example.com') 
transport = client.get_transport() 
channel = transport.open_session() 
channel.exec_command("tail -f /var/log/everything/current") 
while True: 
    rl, wl, xl = select.select([channel],[],[],0.0) 
    if len(rl) > 0: 
     # Must be stdout 
     print channel.recv(1024) 

L'oggetto canale possono essere letti e scritti, il collegamento con stdout e stdin del comando remoto. È possibile ottenere a stderr chiamando channel.makefile_stderr(...).

Ho impostato il timeout su 0.0 secondi perché è stata richiesta una soluzione non bloccante. A seconda delle esigenze, potresti voler bloccare con un timeout diverso da zero.

+0

non è possibile selezionare sull'oggetto stdout, perché manca un attributo fileno. goathens non sta usando un oggetto canale. – JimB

+0

Ho modificato e ampliato l'esempio e l'ho testato per assicurarmi che funzioni :). –

+0

Funziona con stderr anche se si sostituisce rl con xl? –

6

Solo un piccolo aggiornamento alla soluzione di Andrew Aylett. Il seguente codice interrompe effettivamente il ciclo e si chiude quando termina il processo esterno:

import paramiko 
import select 

client = paramiko.SSHClient() 
client.load_system_host_keys() 
client.connect('host.example.com') 
channel = client.get_transport().open_session() 
channel.exec_command("tail -f /var/log/everything/current") 
while True: 
    if channel.exit_status_ready(): 
     break 
    rl, wl, xl = select.select([channel], [], [], 0.0) 
    if len(rl) > 0: 
     print channel.recv(1024) 
+2

Perché non solo fare 'while non channel.exit_status_ready():'? – azmeuk

+0

Inoltre, vedere http://stackoverflow.com/questions/760978/long-running-ssh-commands-in-python-paramiko-module-and-how-to-end-them#comment64123397_766255 – azmeuk

+1

@azmeuk Entrambe le soluzioni sono leggermente errato, perché non si desidera interrompere la ricezione dell'output non appena lo stato di uscita è pronto. Si desidera interrompere quando non vi è alcun output da ricevere E lo stato di uscita è pronto. Altrimenti potresti finire di uscire prima di ricevere tutti i risultati. – user7610