2011-06-22 90 views
5

我試圖使用paramiko python模塊(1.7.7.1)並行執行一組遠程服務器的命令和/或xfer文件。一個任務是這樣的:多進程模塊與paramiko

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() 

「目標文件」 包含,除其他事項外,一個的paramiko SSHClient,運輸和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中的問題,或者我誤解/誤用多處理模塊嗎?任何人都願意提出一個實用的解決方法嗎?非常感謝,

回答

5

UPDATE:作爲@ento筆記,叉形SSH軟件包已經merged back into paramiko所以下面的答案是現在無關,你現在應該被再次使用的paramiko。

這是的paramiko是現在只是被稱爲 ssh package on pypi(這使事情1.7.11版本的已知問題已得到修復的paramiko(在1.7.7.1版本停滯)的一個分支本文)。

顯然有一些重要補丁進入主線Paramiko並且維護者沒有響應,因此Fabric的維護者 @bitprophet在新包名 ssh package on pypi下分配了Paramiko。你可以看到你提到的具體問題是 discussed here,這也是他決定分手的原因之一。如果你真的想要,你可以閱讀 gory details

+2

+1,主要是因爲我不知道的paramiko已被@ bitprophet的SSH軟件包取代 –

+1

PyPI上的SSH軟件包(測試版本1.7.11,1.7.13)給出了與問題中提到的相同的錯誤,至少在Python 2.7.1中。 – ifischer

+1

pypi上的ssh包[已合併回上游](http://bitprophet.org/blog/2012/09/29/paramiko-and-ssh/)作爲paramiko v1.8.0 – ento

1

作爲Paramiko issue中的一個註釋,RNG錯誤可以通過在每個進程中打開一個單獨的ssh句柄來避免,然後paramiko不會再抱怨了。 此示例腳本演示了這一點(我使用一個游泳池,而不是過程):

#!/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)