【问题标题】:Zombie ssh process using python subprocess.Popen使用 python subprocess.Popen 的僵尸 ssh 进程
【发布时间】:2016-02-26 07:14:25
【问题描述】:

我有一个使用 2 台不同机器运行测试用例的脚本。测试需要在机器 2 上运行命令之前在机器 1 上运行一些命令,然后机器 1 将数据发送到机器 2。目标是能够从任何一台机器上运行测试,所以我想我会 ssh 到机器 1 和在那里执行命令,然后 ssh 到机器 2 并在那里执行命令...我试图避免使用 paramiko,因为我不想要那种额外的依赖,所以我发现了这段漂亮的代码,它可以完成工作:

def executeRemoteCommand(host, command):
  ssh = subprocess.Popen(["ssh", "%s" % host, command],
                         shell=False,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

这是我正在做的一个例子:

executeRemoteCommand(user@machine1, "cd /dcd-netapp1/test/test-priority_v6; ./prerun")
time.sleep(30)  
executeRemoteCommand(user@machine2, "cd /dcd-netapp1/test/test-priority-v6; ./run")
time.sleep(1800)
executeRemoteCommand(user@machine1, "cd /dcd-netapp1/test/test-priority-v6; ./postrun")
executeRemoteCommand(user@machine2, "cd /dcd-netapp1/test/test-priority-v6; ./graph_results")

问题是我的prerun ssh 会话没有被终止。 postrun 脚本负责终止使用 prerun 脚本启动的日志记录脚本,但就像我说的,当我使用 ps -ef | grep ssh

对于一些额外的信息,我曾经在executeRemoteCommand 函数中有这段代码:

result = ssh.stdout.readlines()
if result == []:
  error = ssh.stderr.readlines()
  print >>sys.stderr, "ERROR: %s" % error
else:
  print result

我将其注释掉是因为prerun 脚本会挂起,等待将标准输出放入结果中。这永远不会发生。我的prerun 脚本确实有标准输出,但我认为它无法收集它,因为它可能是一种守护进程?我不太了解prerun 脚本。

【问题讨论】:

  • 这里有一些可能有用的示例代码:github.com/NVIDIA/DIGITS/blob/v3.0.0-rc.1/digits/…
  • 您希望您的命令终止吗?如果是这样, readlines 的事情应该工作。我的猜测是 ssh 被阻止等待密码。您可以使用ssh-copy-id 启用无密码登录。有一个名为askpass 的程序也可以提供帮助。
  • 是的,我希望 prerun 在我运行 postrun 脚本时终止。我有authorized_keys。正如我想我提到的,没有 readlines 一切正常,但 ssh 不会终止,通常只是 prerun 但现在它们都还活着,应该在很久以前就结束了。
  • 命令在远程端运行完成?如果你不关心 ssh 连接上发生了什么,你可以使用nohup 在后台运行。摆脱管道也是一个好主意,比如subprocess.Popen("nohup", ["ssh", "%s" % host, command], shell=False, stdout=open(subprocess.DEVNULL, 'wb'), stderr=subprocess.STDOUT)
  • 本地机器上的ssh是僵尸吗? ps x 条目为“Z”?

标签: python ssh subprocess popen zombie-process


【解决方案1】:

移除管道对我的场景有效。现在,我从开始测试的机器上的远程机器上获得所有输出,一切都优雅地结束了。顺便说一句,我发现 shell=False 默认为 false,因此它是不必要的,%s % host 字符串替换也是如此。这是与我的确切问题有关的样子:

def executeRemoteCommand(host, command):
  ssh = subprocess.Popen(["ssh", host, command])

由于该功能现在超级简化,我更进一步,认为如果我完全摆脱该功能并直接使用Popen,则测试更易于阅读:

subprocess.Popen(["ssh", user@machine1, "cd /dcd-netapp1/test/test-priority-v6; ./prerun"])
time.sleep(5)
subprocess.Popen(["ssh", user@machine2, "cd /dcd-netapp1/test/test-priority-v6; ./run"])
time.sleep(1800)
subprocess.Popen(["ssh", user@machine1, "cd /dcd-netapp1/test/test-priority-v6; ./postrun"])
subprocess.Popen(["ssh", user@machine1, "cd /dcd-netapp1/test/test-priority-v6; ./graph_results"])

【讨论】:

  • 为了避免僵尸,你必须最终调用.wait()方法,或者如果你想按顺序调用命令然后使用subprocess.check_call(['ssh', ...])而不是subprocess.Popen() + time.sleep()
猜你喜欢
  • 2019-11-17
  • 2018-06-06
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
相关资源
最近更新 更多