2011-01-06 22 views
12

Şimdi birkaç kutuda çalışan işlemleri izlemek için gereken bir bükülmüş uygulama var. Manuel olarak yaptığım şey 'ssh ve ps' dir, şimdi twisted uygulamamın yapılmasını istiyorum. 2 seçeneğim var.Twisted'den ssh ile uzak komutları çalıştırmanın en iyi yolu?

kullanın paramiko ya ben gerçekten twisted.conch kullanmak istiyorum twisted.conch

gücünü yükselten ama araştırmalarım onun öncelikle SSHServers ve SSHClients oluşturmak amaçlanmaktadır inanmak götürdü. Benim gereksinimi basit remoteExecute(some_cmd)

olduğunu Ancak paramiko kullanarak bunu nasıl anlamaya başardı ama kullanarak twisted.conch

Kod parçacıkları kullanarak bunu nasıl bakıyor önce benim bükülmüş app paramiko sopa istemiyordu twisted ssh kullanarak remote_cmds çalıştırmak için çok takdir edilecektir. Teşekkürler.

cevap

16

Takip - Mutlu bir şekilde, aşağıda atıfta bulunulan bilet şimdi çözülmüştür. Daha basit API, Twisted'in bir sonraki sürümüne dahil edilecektir. Orijinal cevap hala Conch'i kullanmak için geçerli bir yoldur ve neler olup bittiği ile ilgili bazı ilginç detayları açığa çıkarabilir, ancak Twisted 13.1 ve ondan sadece bir komut çalıştırmak ve eğer I/O, this simpler interface will work. Conch istemci API'lerini kullanarak bir SSH üzerinde bir komut yürütmek için maalesef büyük miktarda kod alır. Conch, sadece mantıklı sıkıcı varsayılan davranışı istiyorsanız bile, birçok farklı katmanla uğraşmanızı sağlar. Ancak, kesinlikle mümkün.

import sys, os 

from zope.interface import implements 

from twisted.python.failure import Failure 
from twisted.python.log import err 
from twisted.internet.error import ConnectionDone 
from twisted.internet.defer import Deferred, succeed, setDebugging 
from twisted.internet.interfaces import IStreamClientEndpoint 
from twisted.internet.protocol import Factory, Protocol 

from twisted.conch.ssh.common import NS 
from twisted.conch.ssh.channel import SSHChannel 
from twisted.conch.ssh.transport import SSHClientTransport 
from twisted.conch.ssh.connection import SSHConnection 
from twisted.conch.client.default import SSHUserAuthClient 
from twisted.conch.client.options import ConchOptions 

# setDebugging(True) 


class _CommandTransport(SSHClientTransport): 
    _secured = False 

    def verifyHostKey(self, hostKey, fingerprint): 
     return succeed(True) 


    def connectionSecure(self): 
     self._secured = True 
     command = _CommandConnection(
      self.factory.command, 
      self.factory.commandProtocolFactory, 
      self.factory.commandConnected) 
     userauth = SSHUserAuthClient(
      os.environ['USER'], ConchOptions(), command) 
     self.requestService(userauth) 


    def connectionLost(self, reason): 
     if not self._secured: 
      self.factory.commandConnected.errback(reason) 



class _CommandConnection(SSHConnection): 
    def __init__(self, command, protocolFactory, commandConnected): 
     SSHConnection.__init__(self) 
     self._command = command 
     self._protocolFactory = protocolFactory 
     self._commandConnected = commandConnected 


    def serviceStarted(self): 
     channel = _CommandChannel(
      self._command, self._protocolFactory, self._commandConnected) 
     self.openChannel(channel) 



class _CommandChannel(SSHChannel): 
    name = 'session' 

    def __init__(self, command, protocolFactory, commandConnected): 
     SSHChannel.__init__(self) 
     self._command = command 
     self._protocolFactory = protocolFactory 
     self._commandConnected = commandConnected 


    def openFailed(self, reason): 
     self._commandConnected.errback(reason) 


    def channelOpen(self, ignored): 
     self.conn.sendRequest(self, 'exec', NS(self._command)) 
     self._protocol = self._protocolFactory.buildProtocol(None) 
     self._protocol.makeConnection(self) 


    def dataReceived(self, bytes): 
     self._protocol.dataReceived(bytes) 


    def closed(self): 
     self._protocol.connectionLost(
      Failure(ConnectionDone("ssh channel closed"))) 



class SSHCommandClientEndpoint(object): 
    implements(IStreamClientEndpoint) 

    def __init__(self, command, sshServer): 
     self._command = command 
     self._sshServer = sshServer 


    def connect(self, protocolFactory): 
     factory = Factory() 
     factory.protocol = _CommandTransport 
     factory.command = self._command 
     factory.commandProtocolFactory = protocolFactory 
     factory.commandConnected = Deferred() 

     d = self._sshServer.connect(factory) 
     d.addErrback(factory.commandConnected.errback) 

     return factory.commandConnected 



class StdoutEcho(Protocol): 
    def dataReceived(self, bytes): 
     sys.stdout.write(bytes) 
     sys.stdout.flush() 


    def connectionLost(self, reason): 
     self.factory.finished.callback(None) 



def copyToStdout(endpoint): 
    echoFactory = Factory() 
    echoFactory.protocol = StdoutEcho 
    echoFactory.finished = Deferred() 
    d = endpoint.connect(echoFactory) 
    d.addErrback(echoFactory.finished.errback) 
    return echoFactory.finished 



def main(): 
    from twisted.python.log import startLogging 
    from twisted.internet import reactor 
    from twisted.internet.endpoints import TCP4ClientEndpoint 

    # startLogging(sys.stdout) 

    sshServer = TCP4ClientEndpoint(reactor, "localhost", 22) 
    commandEndpoint = SSHCommandClientEndpoint("/bin/ls", sshServer) 

    d = copyToStdout(commandEndpoint) 
    d.addErrback(err, "ssh command/copy to stdout failed") 
    d.addCallback(lambda ignored: reactor.stop()) 
    reactor.run() 



if __name__ == '__main__': 
    main() 

Bazı şeyler bu konuda dikkat edilmesi gereken:

  • O Twisted 10.1 tanıtılan yeni uç nokta API'leri kullanır İşte bu davayı basitleştirmek için bitirip Twisted eklemek istiyordum bazı kod . Bunu doğrudan reactor.connectTCP üzerinden yapmak mümkündür, ancak bunu daha kullanışlı hale getirmek için bir son nokta olarak yaptım; uç noktalar, aslında bir bağlantı bilgisini isteyen kod olmadan kolayca değiştirilebilir.
  • Hiçbir ana anahtar doğrulaması yok! _CommandTransport.verifyHostKey, bunu uygulayacağınız yerdir. Ne tür şeyler yapmak istediğinize dair bazı ipuçları için twisted/conch/client/default.py'a bir göz atın.
  • Parametre olmak isteyebileceğiniz uzak kullanıcı adı olmak $USER alır.
  • Muhtemelen yalnızca anahtar kimlik doğrulamasıyla çalışır. Parola kimlik doğrulamasını etkinleştirmek isterseniz, muhtemelen bir şey yapmak için SSHUserAuthClient alt sınıfını ve getPassword'u geçersiz kılmanız gerekir.
  • Hemen hemen tüm SSH ve Conch katmanları burada görebilir:
    • _CommandTransport alt SSH taşıma protokolü uygulayan bir düz eski protokol yer almaktadır. Protokolün SSH bağlantısı anlaşması parçalarını uygulayan bir ...
    • _CommandConnection oluşturur. Bu tamamlandığında, yeni açılmış bir SSH kanalıyla konuşmak için bir ...
    • _CommandChannel kullanılır. _CommandChannel, gerçek yürütme komutunu başlatır. Kanal açıldığında, bir örnek oluşturur ...
    • StdoutEcho veya sağladığınız diğer protokoller. Bu protokol, çalıştırdığınız komuttan çıktı alır ve komutun stdinine yazabilir.

az kodla bu destek üzerinde Twisted ilerleme için http://twistedmatrix.com/trac/ticket/4698 bakınız.

+0

Çok teşekkürler exarkun! Bana çok garip geldi çünkü haklı olarak söylediğiniz gibi, bu önemsiz şeyden basit, çıkmış bir çözüm olmalı. Bu yönde zaten çalıştığına sevindim. Hızlı yanıt için tekrar teşekkürler. –

İlgili konular