paramiko的多进程模块

时间:2011-06-22 21:06:10

标签: python ssh paramiko

我正在尝试使用paramiko python模块(1.7.7.1)并行执行命令和/或xfer文件到一组远程服务器。一项任务如下:

jobs = []   
for obj in appObjs:
    if obj.stop_app:
        p = multiprocessing.Process(target=exec_cmd, args=(obj, obj.stop_cmd))
        jobs.append(p)
        print "Starting job %s" % (p)
        p.start()

“obj”包含一个paramiko SSHClient,transport和SFTPClient。 appObjs列表包含大约25个这些对象,因此25个连接到25个不同的服务器。

我在回溯

中使用paramiko的transport.py收到以下错误
raise AssertionError("PID check failed. RNG must be re-initialized after fork(). 
Hint:   Try Random.atfork()")

我根据https://github.com/newsapps/beeswithmachineguns/issues/17上的帖子修补了/usr/lib/python2.6/site-packages/paramiko/transport.py,但它似乎没有帮助。我已经验证了上面提到的路径中的transport.py是正在使用的路径。 paramiko邮件列表似乎已经消失。

这在paramiko中看起来像是一个问题,还是我误解/误用了多处理模块?有人愿意建议一个实际的解决方法吗?非常感谢,

2 个答案:

答案 0 :(得分:5)

更新:正如@ento所说,分叉的ssh包已经merged back into paramiko所以下面的答案现在无关紧要,你现在应该再次使用Paramiko了。

<击> 这是Paramiko中的一个已知问题,已经修复了Paramiko的一个分支(停滞在版本1.7.7.1),现在被称为ssh package on pypi(在撰写本文时将其引入1.7.11版本) )。

<击>

显然在主线Paramiko中有一些重要的补丁存在问题而且维护者没有响应,所以Fabric的维护者@bitprophet在新的包名下分叉了Paramiko { {3}}。你可以看到你提到的具体问题是ssh package on pypi,这也是他决定分叉的原因之一;如果你真的想要,你可以阅读discussed here

答案 1 :(得分:1)

正如Paramiko issue中提到的一条评论,每个进程打开一个单独的ssh句柄可以避免RNG错误,然后paramiko不会再抱怨了。 此示例脚本演示了这一点(我使用的是Pool而不是Processes):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import ssh
from multiprocessing import Pool
import getpass

hostnames = [HOST1, HOST2]
user = USERNAME
pw = getpass.getpass("Enter ssh password:")

def processFunc(hostname):
    handle = ssh.SSHClient()
    handle.set_missing_host_key_policy(ssh.AutoAddPolicy())
    handle.connect(hostname, username=user, password=pw)
    print("child")
    stdin, stdout, stderr = handle.exec_command("ls -l /var/log; sleep 5")
    cmdOutput = ""
    while True:
        try:
            cmdOutput += stdout.next()
        except StopIteration:
            break
    print("Got output from host %s:%s" % (hostname, cmdOutput))
    handle.close()

pool = Pool(len(hostnames))
pool.map(processFunc, hostnames, 1)
pool.close()
pool.join()

## If you want to compare speed:
# for hostname in hostnames:
#     processFunc(hostname)