Python-Paramiko-Timeout mit langer Ausführungsdauer, volle Ausgabe erforderlich

Es gibt viele Themen, die einen Teil des Titels berühren, aber nichts, was die ganze Sache befriedigt. Ich drücke einen Befehl auf einem Remote-Server und benötige die vollständige Ausgabe nach einer langen Ausführungszeit von etwa 5 Minuten. Mit Hilfe des Kanals konnte ich eine Zeitüberschreitung einstellen, aber als ich stdout zurücklas, bekam ich nur einen kleinen Teil der Ausgabe. Die Lösung schien darin zu bestehen, auf channel.exit_status_ready () zu warten. Dies funktionierte bei einem erfolgreichen Anruf, aber ein fehlgeschlagener Anruf würde niemals das Kanal-Timeout auslösen. Nachdem ich die Dokumente überprüft habe, gehe ich davon aus, dass das Timeout nur bei einem Lesevorgang funktioniert und das Warten auf den Beendigungsstatus keine Berechtigung hat. Hier ist dieser Versuch:

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

Schön, nicht wahr? Ich wünschte, es hätte funktioniert.

Mein erster Lösungsversuch war, mit time.time () zu starten und dann start - time.time ()> timeout zu überprüfen. Dies scheint unkompliziert zu sein, aber in meiner aktuellen Version gebe ich start - time.time () mit einem festen Timeout aus, der eine Unterbrechung auslösen sollte ... und sehe Unterschiede, die das Timeout verdoppeln und verdreifachen, ohne dass eine Unterbrechung auftritt. Um Platz zu sparen, erwähne ich meinen dritten Versuch, den ich mit diesem zusammengefasst habe. Ich habe hier weiter gelesen, wie man mit select.select auf die Ausgabe wartet, und in der Dokumentation vermerkt, dass es dort auch eine Zeitüberschreitung gibt. Wie Sie im folgenden Code sehen werden, habe ich alle drei Methoden gemischt - Channel Timeout, Time.time Timeout und Select Timeout - und muss den Prozess dennoch beenden. Hier ist der 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

Hier sind einige typische Ausgaben:

[<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

Die oberste Zeile ist [rlist, wlist, elist] von select, die unterste Zeile ist time.time () - start = (time.time () - start). Ich habe diesen Lauf zum Abbruch gebracht, indem ich die Iterationen gezählt und am Ende des Versuchs abgebrochen habe, nachdem ich 1000 Mal eine Schleife durchlaufen hatte. Das Zeitlimit wurde beim Probelauf auf 3 gesetzt. Was beweist, dass wir durch den Versuch kommen, aber offensichtlich funktioniert keiner der drei Wege, die eine Zeitüberschreitung sein sollten.

Zögern Sie nicht, den Code einzugeben, wenn ich etwas grundlegend falsch verstanden habe. Ich möchte, dass dies überpythonisch ist und ich noch lerne.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage