2013-12-17 8 views
4

ssh 명령을 실행하려면 paramiko을 python 데몬 프로세스 내부에서 실행하려고합니다. 나는 데몬에 대해 다음 구현을 사용하고 있습니다 : paramiko이 연결을 시도 할 때 프로그램이 pycrypto 시작 https://pypi.python.org/pypi/python-daemon/Python Daemon 내 Paramiko가 IOError를 발생시킵니다.

Bad file descriptorIOError를 발생시킵니다. 데몬 코드를 제거하면 (마지막 줄의 주석 처리를 제거하고 위의 두 줄을 주석으로 처리) 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은 아무데도 설정되지 않는 것으로 보이는 메모리 위치를 보여줍니다).

답변

2

이것은 실제로 나 자신을 겪고있는 알려진 문제입니다 (이 질문에 나를 이끌었습니다). 기본적으로, 그것은 유닉스 데몬 프로세스의 정의와 paramiko가 랜덤 넘버 생성기 (RNG)를 구현하는 방식과 관계가있다.

PEP 3143 - Standard daemon process library을 참조하는 경우 올바른 데몬이되는 첫 번째 단계는 "열려있는 파일 설명자를 모두 닫는 것"입니다. 불행하게도 이것은 file descriptor를 /dev/urandom으로 닫습니다. 이것은 paramiko에 의해 차례로 사용되는 Crypto 모듈의 RNG에서 사용됩니다.

잠시 동안 몇 가지 해결 방법이 있지만 저자는 현재이 버그를 찾을 시간이 없다고 밝혔습니다 (첫 번째 링크의 마지막 게시물은 작성자의 것이며이 시점에서 8 일입니다). 쓰기).

, 프로세스는 데몬을하게 한 후 import paramiko, 다음은 파일 기술자가 daemonizing 후 오픈 된 것이기 때문에 원하는대로 작동해야하는 경우 모든 파일을 닫습니다 설명자.

@xraj도 발견하고 (위의 첫 번째 링크) daemonizing 때 /dev/urandom에 파일 기술자를 보존하기위한 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')