Ci sono molti argomenti che toccano parte del titolo, ma nulla che soddisfi abbastanza l'intera cosa. Sto premendo un comando su un server remoto e ho bisogno dell'intero output dopo un lungo periodo di esecuzione, diciamo 5 minuti circa. Usando il canale I è stato possibile impostare un timeout, ma quando ho letto indietro lo stdout ho ottenuto solo una piccola porzione di output. La soluzione sembrava essere attesa per channel.exit_status_ready(). Questo ha funzionato su una chiamata riuscita, ma una chiamata fallita non avrebbe mai attivato il timeout del canale. Dopo aver esaminato i documenti, teorizzo che è perché il timeout funziona solo su un'operazione di lettura e l'attesa per lo stato di uscita non è idonea. Ecco il tentativo:Timeout Paramiko Python con esecuzione lunga, necessita di una piena uscita
channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd) # return on this is not reliable
while True:
try:
if channel.exit_status_ready():
if channel.recv_ready(): # so use recv instead...
output = channel.recv(1048576)
break
if channel.recv_stderr_ready(): # then check error
error = channel.recv_stderr(1048576)
break
except socket.timeout:
print("SSH channel timeout exceeded.")
break
except Exception:
traceback.print_exc()
break
Abbastanza, non è vero? Vorrei che funzionasse.
Il mio primo tentativo di soluzione era utilizzare time.time() per iniziare, quindi selezionare start - time.time()> timeout. Questo sembra semplice, ma nella mia versione attuale, produco start - time.time() con un timeout fisso che dovrebbe innescare un'interruzione ... e vedere le differenze che raddoppiano e triplicano il timeout senza interruzioni. Per risparmiare spazio, menzionerò il mio terzo tentativo, che ho raccolto con questo. Ho letto qui sull'uso di select.select per attendere l'output e ho notato nella documentazione che c'è anche un timeout. Come vedrai dal codice qui sotto, ho mescolato tutti e tre i metodi - timeout del canale, time.time timeout e timeout selezionato - ma devo ancora uccidere il processo. Ecco il frankencode:
channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd) # return on this is not reliable
print("{0}".format(cmd))
start = time.time()
while True:
try:
rlist, wlist, elist = select([channel], [], [],
float(timeout))
print("{0}, {1}, {2}".format(rlist, wlist, elist))
if rlist is not None and len(rlist) > 0:
if channel.exit_status_ready():
if channel.recv_ready(): # so use recv instead...
output = channel.recv(1048576)
break
elif elist is not None and len(elist) > 0:
if channel.recv_stderr_ready(): # then check error
error = channel.recv_stderr(1048576)
break
print("{0} - {1} = {2}".format(
time.time(), start, time.time() - start))
if time.time() - start > timeout:
break
except socket.timeout:
print("SSH channel timeout exceeded.")
break
except Exception:
traceback.print_exc()
break
ecco qualche uscita tipica:
[<paramiko.Channel 3 (open) window=515488 -> <paramiko.Transport at 0x888414cL (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>], [], []
1352494558.42 - 1352494554.69 = 3.73274183273
La linea superiore è [rlist, wList, elist] da selezionare, la linea di fondo è time.time() - start = (time.time() - start). Ho fatto in modo che questa corsa si interrompesse contando le iterazioni e rompendo in fondo alla prova dopo averlo ripetuto 1000 volte. il timeout era impostato su 3 nell'esecuzione del campione. Il che dimostra che siamo riusciti a superare la prova, ma ovviamente, nessuno dei tre modi che dovrebbero essere tempistici funziona.
Sentitevi liberi di copiare il codice se ho fondamentalmente frainteso qualcosa. Mi piacerebbe che questo fosse uber-Pythonic e sto ancora imparando.
La mia ricerca è andata nella stessa direzione, ma sto ottenendo "ValoreError: il segnale funziona solo nel thread principale", anche se non sto usando consapevolmente thread nel mio codice. O qualche modulo sta biforcando il processo o questo è un bug. Pensieri? – user1772459
Sì, ho realizzato che anche Python supporta solo i segnali nel thread principale. Se ricevi quel messaggio, immagino che qualcosa generi i fili ad un certo punto. –