我正在尝试使用ssh
在python守护程序进程内执行paramiko
命令。
我正在为守护程序使用以下实现:https://pypi.python.org/pypi/python-daemon/
当程序启动时{J}尝试连接时,pycrypto
会引发IOError
Bad file descriptor
。
如果我删除了守护程序代码(只需取消注释最后一行并对上面的两个进行注释),就会按预期建立ssh
连接。
简短测试程序的代码如下所示:
#!/usr/bin/env python2
from daemon import runner
import paramiko
class App():
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/tty'
self.stderr_path = '/dev/tty'
self.pidfile_path = '/tmp/testdaemon.pid'
self.pidfile_timeout = 5
def run(self):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
ssh.connect("hostname", username="username")
ssh.close()
app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()
#app.run()
跟踪如下所示:
Traceback (most recent call last):
File "./daemon-test.py", line 31, in <module>
daemon_runner.do_action()
File "/usr/lib/python2.7/site-packages/daemon/runner.py", line 189, in do_action
func(self)
File "/usr/lib/python2.7/site-packages/daemon/runner.py", line 134, in _start
self.app.run()
File "./daemon-test.py", line 22, in run
ssh.connect("hostname", username="username")
File "/usr/lib/python2.7/site-packages/paramiko/client.py", line 311, in connect
t.start_client()
File "/usr/lib/python2.7/site-packages/paramiko/transport.py", line 460, in start_client
Random.atfork()
File "/usr/lib/python2.7/site-packages/Crypto/Random/__init__.py", line 37, in atfork
_UserFriendlyRNG.reinit()
File "/usr/lib/python2.7/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 224, in reinit
_get_singleton().reinit()
File "/usr/lib/python2.7/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 171, in reinit
return _UserFriendlyRNG.reinit(self)
File "/usr/lib/python2.7/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 99, in reinit
self._ec.reinit()
File "/usr/lib/python2.7/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 62, in reinit
block = self._osrng.read(32*32)
File "/usr/lib/python2.7/site-packages/Crypto/Random/OSRNG/rng_base.py", line 76, in read
data = self._read(N)
File "/usr/lib/python2.7/site-packages/Crypto/Random/OSRNG/posix.py", line 65, in _read
d = self.__file.read(N - len(data))
IOError: [Errno 9] Bad file descriptor
我猜这与守护进程产生时的流重定向有关。我试图将它们全部设置为/dev/tty
甚至是普通文件,但没有任何效果。
当我用strace
运行程序时,我可以看到某些东西试图关闭文件两次,那是我收到错误的时候。但是我找不到描述符实际指向的文件(strace
显示的内存位置似乎没有在任何地方设置)。
答案 0 :(得分:2)
这是我实际遇到的一个已知问题(这是导致我这个问题的原因)。基本上,它与UNIX守护进程的定义以及paramiko实现其随机数生成器(RNG)的方式有关。
如果您引用PEP 3143 - Standard daemon process library,成为正确守护程序的第一步是“关闭所有打开的文件描述符”。不幸的是,这会将文件描述符关闭到/dev/urandom
,而import paramiko
在加密模块的RNG中使用,后者由paramiko使用。
目前有一些解决方法,但作者表示他目前没有时间去处理这个错误(尽管第一个链接中的最后一篇文章是由作者撰写的,截至撰写本文时为8天) )。
总之,如果在进程成为守护进程后/dev/urandom
,那么它应该按照需要工作,因为在守护进程关闭所有文件描述符之后将打开文件描述符。
用户 @xraj 也有一个hackish,但聪明的解决方法,用于在守护进程时查找并保留文件描述符import os
from resource import getrlimit, RLIMIT_NOFILE
def files_preserve_by_path(*paths):
wanted=[]
for path in paths:
fd = os.open(path, os.O_RDONLY)
try:
wanted.append(os.fstat(fd)[1:3])
finally:
os.close(fd)
def fd_wanted(fd):
try:
return os.fstat(fd)[1:3] in wanted
except OSError:
return False
fd_max = getrlimit(RLIMIT_NOFILE)[1]
return [ fd for fd in xrange(fd_max) if fd_wanted(fd) ]
daemon_context.files_preserve = files_preserve_by_path('/dev/urandom')
:(上面的第一个链接):
{{1}}
答案 1 :(得分:0)
这最近发生在守护进程和多线程应用程序中,它使得分离线程的循环中的质量close()。我在类pipe.PosixPipe中发现了问题。 set()和close()方法之间没有同步。 PosixPipe的方法可以同时读/写并关闭套接字的描述符。 问题已创建:https://github.com/paramiko/paramiko/issues/692 请求拉:https://github.com/paramiko/paramiko/pull/691/files