추가 정보 - 행복하게, 아래에서 참조한 티켓이 해결되었습니다. 더 간단한 API는 Twisted의 다음 릴리스에 포함될 것입니다. 원래의 대답은 여전히 Conch를 사용하는 유효한 방법이며, 진행중인 작업에 대한 흥미로운 세부 사항을 표시 할 수 있지만, 명령을 실행하고 I/O (this simpler interface will work)를 처리하려는 경우 Twisted 13.1 이상에서 나타낼 수 있습니다.
아쉽게도 Conch 클라이언트 API를 사용하여 SSH에서 명령을 실행하는 데 많은 양의 코드가 필요합니다. Conch는 지루하고 지루한 기본 동작을 원할지라도 다양한 레이어를 처리합니다. 그러나 확실히 가능합니다.
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()
어떤 일이에 대한주의 사항 :
- 그것은 트위스트 10.1에 도입 된 새로운 엔드 포인트 API를 사용하여 여기에 내가이 사건을 단순화하기 위해 마치고 트위스트에 추가 했었어 일부 코드는 .
reactor.connectTCP
에서이 작업을 직접 수행 할 수도 있지만, 더 유용하게 사용할 끝점으로 사용했습니다. 엔드 포인트는 실제로 연결을 알기 원하는 코드없이 쉽게 스와핑 할 수 있습니다.
- 호스트 키 확인이 전혀 없습니다!
_CommandTransport.verifyHostKey
은이를 구현할 곳입니다. 어떤 종류의 일을하고 싶은지 힌트를 얻으려면 twisted/conch/client/default.py
을보십시오.
- 원격 사용자 이름으로
$USER
이 필요하며 이는 매개 변수가 될 수 있습니다.
- 아마도 키 인증에서만 작동합니다. 암호 인증을 사용하려면
SSHUserAuthClient
의 서브 클래스를 만들고 getPassword
을 대체해야합니다.
- 는 거의 모든 SSH와 조가의 층의 여기 볼 수 있습니다 :
_CommandTransport
하단의 SSH 전송 프로토콜을 구현하는 평범한 구식 프로토콜이다. ...
_CommandConnection
프로토콜의 SSH 연결 협상 부분을 구현합니다. 완료되면 ...
_CommandChannel
새로 열린 SSH 채널과 통신하는 데 사용됩니다. _CommandChannel
명령을 실행하기 위해 실제 exec를 수행합니다. 채널이 열리면 인스턴스가 생성됩니다.
StdoutEcho
또는 다른 프로토콜을 제공하십시오. 이 프로토콜은 사용자가 실행 한 명령의 출력을 가져오고 명령의 표준 입력에 쓸 수 있습니다.
적은 코드로이 지원에 트위스트 진전을 위해 http://twistedmatrix.com/trac/ticket/4698를 참조하십시오.
감사합니다. exarkun! 당신이 옳게 언급했듯이,이 사소한 일의 단순하고 즉각적인 해결책이 있어야하기 때문에 그것은 정말 이상합니다. 그 방향으로 이미 효과가 있다니 다행이다. 신속한 대응에 다시 한번 감사드립니다. –