【发布时间】:2014-10-09 22:17:56
【问题描述】:
让我从这个开始……我根本不懂 Python;我在兜圈子,我根本不明白。我对替代和更简单的方法完全开放。
我的目标:连接到不同的服务器,在每个服务器上运行相同的命令,然后(如现在/还没有)将输出用于生产性事情。太棒了。
我有什么:在某处找到了一些代码(我会尝试找到一个链接并更新它)。我稍微修改了一下。它连接到不同的服务器,运行相同的命令。
问题:我不知道一旦一切完成后如何停止反应器。我真的想在不按cntrl+c 的情况下停止它。我想我需要推迟一些事情,但我不知道什么或在哪里。我觉得当 SSHChannel 关闭时,需要以某种方式冒泡到 SSHConnection,以停止服务......所以传输可以知道发生了什么?而且我一直想以某种方式将每个 reactor.connectTCP(server, 22, factory) 包装成一个 deferred 。而且我觉得我可能需要一个控制器类。我尝试了这些东西,但没有正确尝试。也许gatherResults 可能会有所帮助,但是,我不知道到底该放什么。
from twisted.conch.ssh import transport, connection, userauth, channel, common
from twisted.internet import defer, protocol, reactor
import sys, struct
USER = 'username'
PASS = 'thisisforpersonalusesoicanstoreit!'
CMD = 'echo "merely this and nothing more"'
from twisted.python import log
import sys
log.startLogging(sys.stdout)
class ClientCommandTransport(transport.SSHClientTransport):
def __init__(self, username, password, command):
self.username = username
self.password = password
self.command = command
def verifyHostKey(self, pubKey, fingerprint):
print fingerprint
return defer.succeed(True)
def connectionSecure(self):
self.requestService(
PasswordAuth(self.username, self.password,
ClientConnection(self.command)))
class PasswordAuth(userauth.SSHUserAuthClient):
def __init__(self, user, password, connection):
userauth.SSHUserAuthClient.__init__(self, user, connection)
self.password = password
def getPassword(self, prompt=None):
return defer.succeed(self.password)
class ClientConnection(connection.SSHConnection):
def __init__(self, cmd, *args, **kwargs):
connection.SSHConnection.__init__(self)
self.command = cmd
def serviceStarted(self):
self.openChannel(CommandChannel(self.command, conn=self))
class CommandChannel(channel.SSHChannel):
name = 'session'
def __init__(self, command, *args, **kwargs):
channel.SSHChannel.__init__(self, *args, **kwargs)
self.command = command
self.data = ''
def channelOpen(self, data):
self.conn.sendRequest(
self, 'exec', common.NS(self.command), wantReply=True).addCallback(
self._gotResponse)
def _gotResponse(self, _):
self.conn.sendEOF(self)
self.loseConnection()
def dataReceived(self, data):
#self.data += data
print data
def request_exit_status(self, data):
(status,) = struct.unpack('>L', data)
# print 'exit status = ', status
class ClientCommandFactory(protocol.ClientFactory):
def __init__(self, command=CMD):
self.username = USER
self.password = PASS
self.command = command
def buildProtocol(self, addr):
protocol = ClientCommandTransport(
self.username, self.password, self.command)
return protocol
masters = ['server1','server2','server3','server4','server5']
factory = ClientCommandFactory()
for server in masters:
print server
reactor.connectTCP(server, 22, factory)
reactor.run()
我确实玩过延迟 getPage 的 http 请求(确实有效),但我似乎无法通过反应器和 ssh 连接重新应用它。
这些是我真正希望我能理解的资源:
- http://twistedmatrix.com/documents/current/api/twisted.internet.defer.gatherResults.html
- http://mumak.net/stuff/twisted-disconnect.html
- Python Twisted Stopping The Reactor With Multiple Clients
- Best way to run remote commands thru ssh in Twisted?
- What is the correct way to close a Twisted conch SSH connection?
- 以及所有扭曲的类定义..
有了下面的一个答案...我测试了传递对工厂的引用,如果工厂在其数组中没有更多连接(或任何 python调用数组)。
我将工厂更新为现在也包含此方法:
class ClientCommandFactory(protocol.ClientFactory):
def clientConnectionLost(self, connector, reason):
print reason
我查看了日志记录,因为我通常对正在发生的事情感兴趣并且...(其中一些是我自己的陈述,一些是默认的)
014-10-16 13:42:58-0500 [SSHChannel session (0) on SSHService ssh-connection on ClientCommandTransport,client] closed last TCP connection
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] service stopped
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] connection lost
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost.
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] ]
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] connection lost
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost.
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] ]
2014-10-16 13:42:58-0500 [ClientCommandTransport,client] Stopping factory <__main__.ClientCommandFactory instance at 0x02323030>
2014-10-16 13:42:58-0500 [-] Main loop terminated.
所以...它说连接以不干净的方式丢失。有没有更好的方法让我停下来..?
【问题讨论】:
-
我大约一周前写了这个问题......决定放弃它,因为 paramiko。刚刚意识到我需要使用相同的连接运行多个命令(
&&连接还不够)。我仍然真的不知道该怎么办。最终,我想根据命令的响应来处理断开连接,但这些都不重要。 -
你检查this了吗?可能你必须自己实现一些东西才能优雅地关闭连接。无论如何,这与工作完成后停止反应堆无关。
-
@koleS - 谢谢,我没看到。我尝试在下面有人给我的答案中应用这些东西,但反应堆偶尔会过早停止,因为在第一个或两个完成后并非所有连接都已添加。到处都是这么多事情,我不确定在哪里或如何捕获或管理事情。