2016-04-21 10 views
2

Ich habe diese Klasse die ich geschrieben habe:Keine von Paramikos Read-Methoden funktionieren für mich?

class Remote(object): 
    def __init__(self, address, username, password): 
     self.address = address 
     self.username = username 
     self.password = password 

    def stdout(self, s): 
     print('out: ' + s) 

    def stderr(self, s): 
     print('err: ' + s) 

    def sh(self, s): 
     from paramiko import AutoAddPolicy, SSHClient 
     from threading import Thread 
     from time  import sleep 

     ssh = SSHClient() 
     ssh.set_missing_host_key_policy(AutoAddPolicy()) 
     ssh.connect(self.address, username = self.username, password = self.password) 
     stdin, stdout, stderr = ssh.exec_command(s) 

     def monitor(channel, method): 
      while True: 
       for line in channel.readlines(): 
        method(line) 
       sleep(1) 

     Thread(target = monitor, args = (stdout, self.stdout)).start() 
     Thread(target = monitor, args = (stderr, self.stderr)).start() 

Dann habe ich es so versuchen laufen:

>>> from remote import Remote 
>>> address = <removed> 
>>> username = 'root' 
>>> password = <removed> 
>>> r = Remote(address, username, password) 
>>> r.sh('echo Hello') 

Und ich bekomme keine Ausgabe. Wenn ich den Monitor Methode ändern, um so statt:

for line in channel.readlines(): 
    method(line) 

habe ich einfach method(channel.read()) oder method(channel.readline()), aber in diesem Fall, ich sehe gerade:

out: 
err: 

einmal pro Sekunde - es nie wirklich gibt mir die erwarteten Ergebnisse:

out: Hello 

ich weiß, dass meine Adresse, Benutzername und Passwort ist alles in Ordnung, weil ich sie in fabric ganz gut ernähren kann.

>>> from fabric.api  import env 
>>> from fabirc.operations import sudo 
>>> env.host_string, env.user, env.password = address, username, password 
>>> sudo('echo Hello') 
[<omitted>]: Hello 

Was bin ich in meiner paramiko basierten Klasse falsch zu machen, die fabric offenbar der Lage ist, zu behandeln?

bearbeiten

möchte ich die Methode von asynchron. Es sollte sofort zurückkehren. Zum Beispiel, wenn ich dies tun:

r1 = Remote(<one set of credentials removed>) 
r2 = Remote(<another set of credentials removed>) 
r1.sh('echo Hello; sleep 5; echo World') 
r2.sh('echo Hello; sleep 5; echo World') 

Dann sollten die Ergebnisse sein:

out: Hello 
out: Hello 
out: World 
out: World 

anzeigt, dass die zwei Anrufe parallel liefen, nicht:

out: Hello 
out: World 
out: Hello 
out: World 

die darauf hindeuten würde, dass Die beiden Anrufe liefen synchron.

Antwort

1

Das Problem ist, dass while True Schleife in monitor verhindert, dass der Thread endet. Beim Verlassen des ersten Teils wie und Ändern der letzten Zeilen:

def monitor(channel, method): 
    while True: 
     l = channel.readline() 
     if l: 
      method(l) 
     else: 
      break 
tout = Thread(target = monitor, args = (stdout, self.stdout)) 
terr = Thread(target = monitor, args = (stderr, self.stderr)) 
tout.start() 
terr.start() 
tout.join() 
terr.join() 
ssh.close() 

wird die Ausgabe der gegebenen Befehl Zeile für Zeile drucken, während es etwas gibt, zurückgegeben werden.

+0

Ich möchte die Methoden asynchron ausführen lassen. Es sollte nicht warten, bis der Befehl beendet ist. Wenn sich der Benutzer der Klasse darum kümmert, was der Befehl ausgibt, sollte er die Methoden 'stdout' oder' stderr' ableiten und verwenden. – ArtOfWarfare

+0

@ArtOfWarfare Verstanden, siehe Bearbeitungen – fernandezcuesta

+0

Ich glaube nicht, dass Sie verstehen - das führt immer noch dazu, dass die Anrufe synchron sind. Ich habe eine Änderung zu meiner Frage hinzugefügt, um sie zu erklären. Allerdings gibt Ihr Code tatsächlich etwas aus, während mein ursprünglicher Code nichts ausgibt, also +1 dafür. Außerdem werde ich Sie wissen lassen, dass das Synchronisieren eigentlich ziemlich einfach war. Ich musste nur den Namen von 'sh' in' _sh' ändern (um anzuzeigen, dass es privat ist) und ein neues 'sh' machen, das nur einen Thread startet und' _sh' darauf ausführt, dann ohne Verbindung zurückkehrt. Nicht sicher, ob das die eleganteste Lösung ist oder nicht, aber es scheint zu funktionieren. – ArtOfWarfare