这个问题是这个问题的后续问题:Using paramiko to send commands to an open shell that has an interactive element所以请在回答之前先阅读。
我能够成功地将数据发送到阵列的系统shell,但是当阵列花费太长时间来运行我发送的脚本时,我需要帮助确定如何实现超时。 Paramiko的exec_command
有一个timeout=
参数,但这不会有帮助,因为我发送的唯一命令是"script"
,它立即返回并等待通道上的输入,当我尝试实现它似乎打破了函数的其余部分,因为没有从数组返回。
然后该数组应该处理我发送的脚本并通过stdout
返回输出,但是如果数组需要很长时间,我就无法超时连接,并且它保持不变脚本的其余部分。
这是我的代码:
def run_script(self, script_name):
""" Run a script on the remote array and return the stdout
"""
try:
common_functions_file = os.path.join(SCRIPT_DIR, 'zfs_common_functions.js')
common_functions = open(common_functions_file).read().splitlines()
# add common_functions to the top of the script
script_contents = common_functions + open(script_name).read().splitlines()
stdin, stdout, stderr = self._ssh.exec_command('script')
for line in script_contents:
# Skip lines with comments
if re.match("^//", line):
continue
stdin.write(line)
stdin.write('\n')
stdin.write('.\n')
stdin.flush()
error = stderr.readlines()
if len(error) == 0:
try:
output = ''.join(stdout.readlines())
if(re.search('aksh', output)):
logger.warn("ZFS Shell Error: %s" % output)
return None
return output
except Exception as e:
logger.exception(e)
else:
logger.error(error)
return None
except paramiko.SSHException as e:
logger.warn(
"Couldn't execute script on array %s: %s" % (array.name, e))
except AttributeError as e:
logger.exception(e)
raise
except Exception:
raise
答案 0 :(得分:2)
我最终通过直接与频道进行交互来解决问题,您可以设置超时:
def run_script(self, script_name):
""" Run a script on the remote array and return the stdout
"""
try:
chan = self._ssh.get_transport().open_session()
# five minute timeout on the channel communication
chan.settimeout(5*60.0)
common_functions_file = os.path.join(SCRIPT_DIR, 'zfs_common_functions.js')
common_functions = open(common_functions_file).read().splitlines()
# add common_functions to the top of the script
script_contents = common_functions + open(script_name).read().splitlines()
chan.exec_command('script')
if chan.send_ready():
chan.sendall("\n".join(script_contents))
chan.send("\n.\n")
results = StringIO()
error = StringIO()
bufsize = 1024
while not chan.exit_status_ready():
if chan.recv_ready():
data = chan.recv(bufsize)
while data:
results.write(data)
data = chan.recv(bufsize)
if chan.recv_stderr_ready():
error_buf = chan.recv_stderr(bufsize)
while error_buf:
error.write(error_buf)
error_buf = chan.recv_stderr(bufsize)
exit_status = chan.recv_exit_status()
if exit_status == 0:
return results.getvalue()
else:
raise ZfsScriptError(results.getvalue())
except socket.timeout:
logger.warn("%s: Timeout running %s" %(self.hostname, script_name))
return None
except paramiko.SSHException as e:
logger.warn(
"Couldn't execute script on array %s: %s" % (self.hostname, e))
raise
except AttributeError as e:
logger.exception(e)
raise
except Exception:
raise
finally:
results.close()
error.close()
chan.close()