常常使用paramiko工具对几百台设备进行管理。主要是天天到上边取文件过来,做为备份。服务器
今天发现程序运行了10个小时尚未结束,就上去看一个究竟。session
查看日志,发如今取一台服务器上的文件时卡在那里了。本身手动ssh登陆上去,执行了一个ls命令就卡住了,ssh
原来是这个服务器的硬盘出问题了。怪不得取不到文件。socket
可是想一想,程序应该是在一段时间内读取不到数据就超时退出的阿,怎么会卡在那里呢。找到执行命令的那段工具
sin, sout, serr = ssh.exec_command('tar -zc0 /data/important-file.txt')this
这条语句是过去了,可是后边日志
sout.read(10240)继承
这条语句一直卡在那里,不动弹了。看来sout是没有设置超时的。查查paramiko的源代码吧。找了一下,在client.py中ip
def exec_command(self, command, bufsize=-1)rem
chan = self._transport.open_session()
chan.exec_command(command)
stdin = chan.makefile('wb', bufsize)
stdout = chan.makefile('rb', bufsize)
stderr = chan.makefile_stderr('rb', bufsize)
return stdin, stdout, stderr
那个stout就是chan.makefile()出来的。继续看makefile
def makefile(self, *params):
return ChannelFile(*([self] + list(params)))
这里看不出什么,重点在ChannelFile的read方法上,查到read方法。ChannelFile继承了BufferedFile,由于文档中写道,这个
ChannelFile是个file-like的object, 因此_read方法应该是实际read去调用的方法。看代码
def _read(self, size):
return self.channel.recv(size)
很简单,是channel的recv方法(这个channel就是makefile时的第一个参数self,也就是transport.open_session()出来的那个chan)。
仍是回到Channel去,recv方法
def recv(self, nbytes):
try:
out = self.in_buffer.read(nbytes, self.timeout)
except PipeTimeout, e:
raise socket.timeout()
ack = self._check_add_window(len(out))
# no need to hold the channel lock when sending this
if ack > 0:
m = Message()
m.add_byte(chr(MSG_CHANNEL_WINDOW_ADJUST))
m.add_int(self.remote_chanid)
m.add_int(ack)
self.transport._send_user_message(m)
return out
从黑体的部分能够看出,原来recv是能够设置timeout的,只是paramiko默认的没有设置而已。好了,把timeout设置上,就OK。
修改了一下paramiko代码,运行了一下,程序也没有卡在那个地方,除了那台出问题的服务器,其他的都正常取到。
修改办法以下,修改client.py的exec_command方法以下
def exec_command(self, command, bufsize=-1, timeout = None ):
chan = self._transport.open_session()
if timeout is not None:
chan.settimeout(timeout)
chan.exec_command(command)
stdin = chan.makefile('wb', bufsize)
stdout = chan.makefile('rb', bufsize)
stderr = chan.makefile_stderr('rb', bufsize)
return stdin, stdout, stderr
黑体部分为增长的部分。而在调用的地方,改成
sin, sout, serr = ssh.exec_command('tar -zc0 /data/important-file.txt', timeout = 20.0 )