parmentelat / apssh

asyncio-based parallel ssh
Other
9 stars 2 forks source link

too many files error on multiple declaration of SshNode() (only on mac) #11

Closed JawaGL closed 6 years ago

JawaGL commented 6 years ago

When using apssh on Mac, this snipet of code :

for i in range(1000):
    node = SshNode(hostname='127.0.0.1') 

Generate an error :

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/local/lib/python3.6/site-packages/apssh/nodes.py", line 165, in __init__
  File "/usr/local/lib/python3.6/site-packages/apssh/keys.py", line 157, in load_private_keys
  File "/usr/local/lib/python3.6/site-packages/apssh/keys.py", line 157, in <listcomp>
  File "/usr/local/lib/python3.6/site-packages/apssh/keys.py", line 35, in import_private_key
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 1161, in open
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 1015, in _opener
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 387, in wrapped
OSError: [Errno 24] Too many open files: '/Users/[****]/.ssh/id_rsa'

Cause

There is a file descriptor that is not closed on the creation of a SshNode as we can see with :

[...]$ lsof -p [PythonPid]
[...]
Python  42078 [...]    4u    unix 0x4537b16394f7d0a3        0t0            ->0x4537b16394f7c67b ##asyncio loop
Python  42078 [...]    5u    unix 0x4537b16394f7c67b        0t0            ->0x4537b16394f7d0a3 ##asyncio loop
Python  42078 [...]    6u    unix 0x4537b16394f7b86b        0t0            ->0x4537b16394f7a8cb ##Remnant fd
Python  42078 [...]    7u    unix 0x4537b16394f7cbf3        0t0            ->0x4537b16394f7d61b ##Remnant fd
Python  42078 [...]    8u    unix 0x4537b16394f7cfdb        0t0            ->0x4537b16394f7c80b ##Remnant fd
Python  42078 [...]    9u    unix 0x4537b16394f7b613        0t0            ->0x4537b16394f7a993 ##Remnant fd

This come from the SSHAgentClient class from asyncssh. More particulary from the getkeys() method. In apssh code it is the await agent_client.get_keys() from the method load_agent_keys(...) in the keys.py file.

It is important to note that this remnant file descriptor happens only on mac.

Possible fix

Closing the SSHAgentClient seems to do the trick (example) but I will ask on asyncssh if it is an expected behavior.

Indeed, we can reproduce this simply by using asyncssh :

loop = asyncio.get_event_loop()
agent_path = os.environ.get('SSH_AUTH_SOCK', None)

async def aget_from_agent(loop,agent_path):
    clientAgent = asyncssh.SSHAgentClient(loop, agent_path)
    keys = await clientAgent.get_keys()

for i in range(1000):
    loop.run_until_complete(aget_from_agent(loop, agent_path))