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.
Ç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. –