Quantcast
Viewing latest article 18
Browse Latest Browse All 34

Paramiko object with Process (RNG must be re-initialized after fork)

When you create an object in Python which will be used later by an object of type Process, that works correctly. Let's see an example where an object of type Process prints an attribute provided by another object belonging to the class A.

frommultiprocessingimport Process

classA():
def__init__(self):
self.my_dict = {"day": "Tuesday"}

classB():
def__init__(self):
self.a = A()
self.__process =None

defstart(self):
self.__process = Process(target=self.__run_process)
self.__process.start()

def__run_process(self):
printself.a.my_dict

if __name__ =="__main__":
b = B()
b.start()


$ python test.py
{'day': 'Tuesday'}


But when that process has to handle a Paramiko object where the connection has been initialized before, will not work.

importparamiko
frommultiprocessingimport Process

classB():
def__init__(self):
self.__process =None
self.__ssh = paramiko.SSHClient()
self.__ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.__ssh.connect('127.0.0.1', username='javi', password='xxxxxx')

defstart(self):
self.__process = Process(target=self.__run_process)
self.__process.start()

def__run_process(self):
try:
_, stdout, _ =self.__ssh.exec_command("hostname")
except:
print"Failed the execution"
else:
print stdout.read()

if __name__ =="__main__":
b = B()
b.start()


$ python test.py
Failed the execution


If you take a look at the output generated by the execution without catching it through an exception, you could observe an error as follows.

$ python test.py 
Process Process-1:
Traceback (most recent call last):
...
raiseAssertionError("PID check failed. RNG must be re-initialized after fork(). Hint: Try Random.atfork()")
AssertionError: PID check failed. RNG must be re-initialized after fork(). Hint: Try Random.atfork()


This is a well-known issue in Paramiko that has been apparently fixed in recent versions (for my tests, I am using the version provided by Ubuntu 12.10 by default: 1.7.7.1-3). A possible workaround will be for example to open a new SSH connection for that process. Let's grab an example.

importparamiko
frommultiprocessingimport Process

classB():
def__init__(self):
self.__process =None
self.__ssh = paramiko.SSHClient()
self.__ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

defstart(self):
self.__process = Process(target=self.__run_process)
self.__process.start()

def__run_process(self):
self.__ssh.connect('127.0.0.1', username='javi', password='xxxxxx')
try:
_, stdout, _ =self.__ssh.exec_command("hostname")
except:
print"Failed the execution"
else:
print stdout.read()

if __name__ =="__main__":
b = B()
b.start()


$ python test.py
javi-pc


As you can see above, the definition of the Paramiko object takes place within the constructor of the class B, but the connection is eventually initialized by the forked process.



Viewing latest article 18
Browse Latest Browse All 34

Trending Articles