We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bring back support OpenSSH Identityfile
# Description

Support for identity file was added in - #2534
And then removed during refactoring in - #2691 

# Proposal

Add it back :) in PR #2846

### General Info

```bash
❯❯❯ docker --version
Docker version 20.10.6, build 370c289

❯❯❯ docker-compose version
docker-compose version 1.29.2, build 5becea4c
docker-py version: 5.0.0
CPython version: 3.9.0
OpenSSL version: OpenSSL 1.1.1h  22 Sep 2020
```
MacOS 11.3.1


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docker/transport/sshconn.py`
Content:
```
1 import paramiko
2 import queue
3 import urllib.parse
4 import requests.adapters
5 import logging
6 import os
7 import signal
8 import socket
9 import subprocess
10 
11 from docker.transport.basehttpadapter import BaseHTTPAdapter
12 from .. import constants
13 
14 import http.client as httplib
15 
16 try:
17     import requests.packages.urllib3 as urllib3
18 except ImportError:
19     import urllib3
20 
21 RecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer
22 
23 
24 class SSHSocket(socket.socket):
25     def __init__(self, host):
26         super().__init__(
27             socket.AF_INET, socket.SOCK_STREAM)
28         self.host = host
29         self.port = None
30         self.user = None
31         if ':' in self.host:
32             self.host, self.port = self.host.split(':')
33         if '@' in self.host:
34             self.user, self.host = self.host.split('@')
35 
36         self.proc = None
37 
38     def connect(self, **kwargs):
39         args = ['ssh']
40         if self.user:
41             args = args + ['-l', self.user]
42 
43         if self.port:
44             args = args + ['-p', self.port]
45 
46         args = args + ['--', self.host, 'docker system dial-stdio']
47 
48         preexec_func = None
49         if not constants.IS_WINDOWS_PLATFORM:
50             def f():
51                 signal.signal(signal.SIGINT, signal.SIG_IGN)
52             preexec_func = f
53 
54         env = dict(os.environ)
55 
56         # drop LD_LIBRARY_PATH and SSL_CERT_FILE
57         env.pop('LD_LIBRARY_PATH', None)
58         env.pop('SSL_CERT_FILE', None)
59 
60         self.proc = subprocess.Popen(
61             ' '.join(args),
62             env=env,
63             shell=True,
64             stdout=subprocess.PIPE,
65             stdin=subprocess.PIPE,
66             preexec_fn=None if constants.IS_WINDOWS_PLATFORM else preexec_func)
67 
68     def _write(self, data):
69         if not self.proc or self.proc.stdin.closed:
70             raise Exception('SSH subprocess not initiated.'
71                             'connect() must be called first.')
72         written = self.proc.stdin.write(data)
73         self.proc.stdin.flush()
74         return written
75 
76     def sendall(self, data):
77         self._write(data)
78 
79     def send(self, data):
80         return self._write(data)
81 
82     def recv(self, n):
83         if not self.proc:
84             raise Exception('SSH subprocess not initiated.'
85                             'connect() must be called first.')
86         return self.proc.stdout.read(n)
87 
88     def makefile(self, mode):
89         if not self.proc:
90             self.connect()
91         self.proc.stdout.channel = self
92 
93         return self.proc.stdout
94 
95     def close(self):
96         if not self.proc or self.proc.stdin.closed:
97             return
98         self.proc.stdin.write(b'\n\n')
99         self.proc.stdin.flush()
100         self.proc.terminate()
101 
102 
103 class SSHConnection(httplib.HTTPConnection):
104     def __init__(self, ssh_transport=None, timeout=60, host=None):
105         super().__init__(
106             'localhost', timeout=timeout
107         )
108         self.ssh_transport = ssh_transport
109         self.timeout = timeout
110         self.ssh_host = host
111 
112     def connect(self):
113         if self.ssh_transport:
114             sock = self.ssh_transport.open_session()
115             sock.settimeout(self.timeout)
116             sock.exec_command('docker system dial-stdio')
117         else:
118             sock = SSHSocket(self.ssh_host)
119             sock.settimeout(self.timeout)
120             sock.connect()
121 
122         self.sock = sock
123 
124 
125 class SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):
126     scheme = 'ssh'
127 
128     def __init__(self, ssh_client=None, timeout=60, maxsize=10, host=None):
129         super().__init__(
130             'localhost', timeout=timeout, maxsize=maxsize
131         )
132         self.ssh_transport = None
133         self.timeout = timeout
134         if ssh_client:
135             self.ssh_transport = ssh_client.get_transport()
136         self.ssh_host = host
137 
138     def _new_conn(self):
139         return SSHConnection(self.ssh_transport, self.timeout, self.ssh_host)
140 
141     # When re-using connections, urllib3 calls fileno() on our
142     # SSH channel instance, quickly overloading our fd limit. To avoid this,
143     # we override _get_conn
144     def _get_conn(self, timeout):
145         conn = None
146         try:
147             conn = self.pool.get(block=self.block, timeout=timeout)
148 
149         except AttributeError:  # self.pool is None
150             raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.")
151 
152         except queue.Empty:
153             if self.block:
154                 raise urllib3.exceptions.EmptyPoolError(
155                     self,
156                     "Pool reached maximum size and no more "
157                     "connections are allowed."
158                 )
159             pass  # Oh well, we'll create a new connection then
160 
161         return conn or self._new_conn()
162 
163 
164 class SSHHTTPAdapter(BaseHTTPAdapter):
165 
166     __attrs__ = requests.adapters.HTTPAdapter.__attrs__ + [
167         'pools', 'timeout', 'ssh_client', 'ssh_params', 'max_pool_size'
168     ]
169 
170     def __init__(self, base_url, timeout=60,
171                  pool_connections=constants.DEFAULT_NUM_POOLS,
172                  max_pool_size=constants.DEFAULT_MAX_POOL_SIZE,
173                  shell_out=False):
174         self.ssh_client = None
175         if not shell_out:
176             self._create_paramiko_client(base_url)
177             self._connect()
178 
179         self.ssh_host = base_url
180         if base_url.startswith('ssh://'):
181             self.ssh_host = base_url[len('ssh://'):]
182 
183         self.timeout = timeout
184         self.max_pool_size = max_pool_size
185         self.pools = RecentlyUsedContainer(
186             pool_connections, dispose_func=lambda p: p.close()
187         )
188         super().__init__()
189 
190     def _create_paramiko_client(self, base_url):
191         logging.getLogger("paramiko").setLevel(logging.WARNING)
192         self.ssh_client = paramiko.SSHClient()
193         base_url = urllib.parse.urlparse(base_url)
194         self.ssh_params = {
195             "hostname": base_url.hostname,
196             "port": base_url.port,
197             "username": base_url.username
198             }
199         ssh_config_file = os.path.expanduser("~/.ssh/config")
200         if os.path.exists(ssh_config_file):
201             conf = paramiko.SSHConfig()
202             with open(ssh_config_file) as f:
203                 conf.parse(f)
204             host_config = conf.lookup(base_url.hostname)
205             self.ssh_conf = host_config
206             if 'proxycommand' in host_config:
207                 self.ssh_params["sock"] = paramiko.ProxyCommand(
208                     self.ssh_conf['proxycommand']
209                 )
210             if 'hostname' in host_config:
211                 self.ssh_params['hostname'] = host_config['hostname']
212             if base_url.port is None and 'port' in host_config:
213                 self.ssh_params['port'] = self.ssh_conf['port']
214             if base_url.username is None and 'user' in host_config:
215                 self.ssh_params['username'] = self.ssh_conf['user']
216 
217         self.ssh_client.load_system_host_keys()
218         self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())
219 
220     def _connect(self):
221         if self.ssh_client:
222             self.ssh_client.connect(**self.ssh_params)
223 
224     def get_connection(self, url, proxies=None):
225         if not self.ssh_client:
226             return SSHConnectionPool(
227                 ssh_client=self.ssh_client,
228                 timeout=self.timeout,
229                 maxsize=self.max_pool_size,
230                 host=self.ssh_host
231             )
232         with self.pools.lock:
233             pool = self.pools.get(url)
234             if pool:
235                 return pool
236 
237             # Connection is closed try a reconnect
238             if self.ssh_client and not self.ssh_client.get_transport():
239                 self._connect()
240 
241             pool = SSHConnectionPool(
242                 ssh_client=self.ssh_client,
243                 timeout=self.timeout,
244                 maxsize=self.max_pool_size,
245                 host=self.ssh_host
246             )
247             self.pools[url] = pool
248 
249         return pool
250 
251     def close(self):
252         super().close()
253         if self.ssh_client:
254             self.ssh_client.close()
255
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docker/transport/sshconn.py b/docker/transport/sshconn.py
--- a/docker/transport/sshconn.py
+++ b/docker/transport/sshconn.py
@@ -205,7 +205,6 @@
             with open(ssh_config_file) as f:
                 conf.parse(f)
             host_config = conf.lookup(base_url.hostname)
-            self.ssh_conf = host_config
             if 'proxycommand' in host_config:
                 self.ssh_params["sock"] = paramiko.ProxyCommand(
                     self.ssh_conf['proxycommand']
@@ -213,9 +212,11 @@
             if 'hostname' in host_config:
                 self.ssh_params['hostname'] = host_config['hostname']
             if base_url.port is None and 'port' in host_config:
-                self.ssh_params['port'] = self.ssh_conf['port']
+                self.ssh_params['port'] = host_config['port']
             if base_url.username is None and 'user' in host_config:
-                self.ssh_params['username'] = self.ssh_conf['user']
+                self.ssh_params['username'] = host_config['user']
+            if 'identityfile' in host_config:
+                self.ssh_params['key_filename'] = host_config['identityfile']
 
         self.ssh_client.load_system_host_keys()
         self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())

{"golden_diff": "diff --git a/docker/transport/sshconn.py b/docker/transport/sshconn.py\n--- a/docker/transport/sshconn.py\n+++ b/docker/transport/sshconn.py\n@@ -205,7 +205,6 @@\n             with open(ssh_config_file) as f:\n                 conf.parse(f)\n             host_config = conf.lookup(base_url.hostname)\n-            self.ssh_conf = host_config\n             if 'proxycommand' in host_config:\n                 self.ssh_params[\"sock\"] = paramiko.ProxyCommand(\n                     self.ssh_conf['proxycommand']\n@@ -213,9 +212,11 @@\n             if 'hostname' in host_config:\n                 self.ssh_params['hostname'] = host_config['hostname']\n             if base_url.port is None and 'port' in host_config:\n-                self.ssh_params['port'] = self.ssh_conf['port']\n+                self.ssh_params['port'] = host_config['port']\n             if base_url.username is None and 'user' in host_config:\n-                self.ssh_params['username'] = self.ssh_conf['user']\n+                self.ssh_params['username'] = host_config['user']\n+            if 'identityfile' in host_config:\n+                self.ssh_params['key_filename'] = host_config['identityfile']\n \n         self.ssh_client.load_system_host_keys()\n         self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())\n", "issue": "Bring back support OpenSSH Identityfile\n# Description\r\n\r\nSupport for identity file was added in - #2534\r\nAnd then removed during refactoring in - #2691 \r\n\r\n# Proposal\r\n\r\nAdd it back :) in PR #2846\r\n\r\n### General Info\r\n\r\n```bash\r\n\u276f\u276f\u276f docker --version\r\nDocker version 20.10.6, build 370c289\r\n\r\n\u276f\u276f\u276f docker-compose version\r\ndocker-compose version 1.29.2, build 5becea4c\r\ndocker-py version: 5.0.0\r\nCPython version: 3.9.0\r\nOpenSSL version: OpenSSL 1.1.1h  22 Sep 2020\r\n```\r\nMacOS 11.3.1\r\n\n", "before_files": [{"content": "import paramiko\nimport queue\nimport urllib.parse\nimport requests.adapters\nimport logging\nimport os\nimport signal\nimport socket\nimport subprocess\n\nfrom docker.transport.basehttpadapter import BaseHTTPAdapter\nfrom .. import constants\n\nimport http.client as httplib\n\ntry:\n    import requests.packages.urllib3 as urllib3\nexcept ImportError:\n    import urllib3\n\nRecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer\n\n\nclass SSHSocket(socket.socket):\n    def __init__(self, host):\n        super().__init__(\n            socket.AF_INET, socket.SOCK_STREAM)\n        self.host = host\n        self.port = None\n        self.user = None\n        if ':' in self.host:\n            self.host, self.port = self.host.split(':')\n        if '@' in self.host:\n            self.user, self.host = self.host.split('@')\n\n        self.proc = None\n\n    def connect(self, **kwargs):\n        args = ['ssh']\n        if self.user:\n            args = args + ['-l', self.user]\n\n        if self.port:\n            args = args + ['-p', self.port]\n\n        args = args + ['--', self.host, 'docker system dial-stdio']\n\n        preexec_func = None\n        if not constants.IS_WINDOWS_PLATFORM:\n            def f():\n                signal.signal(signal.SIGINT, signal.SIG_IGN)\n            preexec_func = f\n\n        env = dict(os.environ)\n\n        # drop LD_LIBRARY_PATH and SSL_CERT_FILE\n        env.pop('LD_LIBRARY_PATH', None)\n        env.pop('SSL_CERT_FILE', None)\n\n        self.proc = subprocess.Popen(\n            ' '.join(args),\n            env=env,\n            shell=True,\n            stdout=subprocess.PIPE,\n            stdin=subprocess.PIPE,\n            preexec_fn=None if constants.IS_WINDOWS_PLATFORM else preexec_func)\n\n    def _write(self, data):\n        if not self.proc or self.proc.stdin.closed:\n            raise Exception('SSH subprocess not initiated.'\n                            'connect() must be called first.')\n        written = self.proc.stdin.write(data)\n        self.proc.stdin.flush()\n        return written\n\n    def sendall(self, data):\n        self._write(data)\n\n    def send(self, data):\n        return self._write(data)\n\n    def recv(self, n):\n        if not self.proc:\n            raise Exception('SSH subprocess not initiated.'\n                            'connect() must be called first.')\n        return self.proc.stdout.read(n)\n\n    def makefile(self, mode):\n        if not self.proc:\n            self.connect()\n        self.proc.stdout.channel = self\n\n        return self.proc.stdout\n\n    def close(self):\n        if not self.proc or self.proc.stdin.closed:\n            return\n        self.proc.stdin.write(b'\\n\\n')\n        self.proc.stdin.flush()\n        self.proc.terminate()\n\n\nclass SSHConnection(httplib.HTTPConnection):\n    def __init__(self, ssh_transport=None, timeout=60, host=None):\n        super().__init__(\n            'localhost', timeout=timeout\n        )\n        self.ssh_transport = ssh_transport\n        self.timeout = timeout\n        self.ssh_host = host\n\n    def connect(self):\n        if self.ssh_transport:\n            sock = self.ssh_transport.open_session()\n            sock.settimeout(self.timeout)\n            sock.exec_command('docker system dial-stdio')\n        else:\n            sock = SSHSocket(self.ssh_host)\n            sock.settimeout(self.timeout)\n            sock.connect()\n\n        self.sock = sock\n\n\nclass SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):\n    scheme = 'ssh'\n\n    def __init__(self, ssh_client=None, timeout=60, maxsize=10, host=None):\n        super().__init__(\n            'localhost', timeout=timeout, maxsize=maxsize\n        )\n        self.ssh_transport = None\n        self.timeout = timeout\n        if ssh_client:\n            self.ssh_transport = ssh_client.get_transport()\n        self.ssh_host = host\n\n    def _new_conn(self):\n        return SSHConnection(self.ssh_transport, self.timeout, self.ssh_host)\n\n    # When re-using connections, urllib3 calls fileno() on our\n    # SSH channel instance, quickly overloading our fd limit. To avoid this,\n    # we override _get_conn\n    def _get_conn(self, timeout):\n        conn = None\n        try:\n            conn = self.pool.get(block=self.block, timeout=timeout)\n\n        except AttributeError:  # self.pool is None\n            raise urllib3.exceptions.ClosedPoolError(self, \"Pool is closed.\")\n\n        except queue.Empty:\n            if self.block:\n                raise urllib3.exceptions.EmptyPoolError(\n                    self,\n                    \"Pool reached maximum size and no more \"\n                    \"connections are allowed.\"\n                )\n            pass  # Oh well, we'll create a new connection then\n\n        return conn or self._new_conn()\n\n\nclass SSHHTTPAdapter(BaseHTTPAdapter):\n\n    __attrs__ = requests.adapters.HTTPAdapter.__attrs__ + [\n        'pools', 'timeout', 'ssh_client', 'ssh_params', 'max_pool_size'\n    ]\n\n    def __init__(self, base_url, timeout=60,\n                 pool_connections=constants.DEFAULT_NUM_POOLS,\n                 max_pool_size=constants.DEFAULT_MAX_POOL_SIZE,\n                 shell_out=False):\n        self.ssh_client = None\n        if not shell_out:\n            self._create_paramiko_client(base_url)\n            self._connect()\n\n        self.ssh_host = base_url\n        if base_url.startswith('ssh://'):\n            self.ssh_host = base_url[len('ssh://'):]\n\n        self.timeout = timeout\n        self.max_pool_size = max_pool_size\n        self.pools = RecentlyUsedContainer(\n            pool_connections, dispose_func=lambda p: p.close()\n        )\n        super().__init__()\n\n    def _create_paramiko_client(self, base_url):\n        logging.getLogger(\"paramiko\").setLevel(logging.WARNING)\n        self.ssh_client = paramiko.SSHClient()\n        base_url = urllib.parse.urlparse(base_url)\n        self.ssh_params = {\n            \"hostname\": base_url.hostname,\n            \"port\": base_url.port,\n            \"username\": base_url.username\n            }\n        ssh_config_file = os.path.expanduser(\"~/.ssh/config\")\n        if os.path.exists(ssh_config_file):\n            conf = paramiko.SSHConfig()\n            with open(ssh_config_file) as f:\n                conf.parse(f)\n            host_config = conf.lookup(base_url.hostname)\n            self.ssh_conf = host_config\n            if 'proxycommand' in host_config:\n                self.ssh_params[\"sock\"] = paramiko.ProxyCommand(\n                    self.ssh_conf['proxycommand']\n                )\n            if 'hostname' in host_config:\n                self.ssh_params['hostname'] = host_config['hostname']\n            if base_url.port is None and 'port' in host_config:\n                self.ssh_params['port'] = self.ssh_conf['port']\n            if base_url.username is None and 'user' in host_config:\n                self.ssh_params['username'] = self.ssh_conf['user']\n\n        self.ssh_client.load_system_host_keys()\n        self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())\n\n    def _connect(self):\n        if self.ssh_client:\n            self.ssh_client.connect(**self.ssh_params)\n\n    def get_connection(self, url, proxies=None):\n        if not self.ssh_client:\n            return SSHConnectionPool(\n                ssh_client=self.ssh_client,\n                timeout=self.timeout,\n                maxsize=self.max_pool_size,\n                host=self.ssh_host\n            )\n        with self.pools.lock:\n            pool = self.pools.get(url)\n            if pool:\n                return pool\n\n            # Connection is closed try a reconnect\n            if self.ssh_client and not self.ssh_client.get_transport():\n                self._connect()\n\n            pool = SSHConnectionPool(\n                ssh_client=self.ssh_client,\n                timeout=self.timeout,\n                maxsize=self.max_pool_size,\n                host=self.ssh_host\n            )\n            self.pools[url] = pool\n\n        return pool\n\n    def close(self):\n        super().close()\n        if self.ssh_client:\n            self.ssh_client.close()\n", "path": "docker/transport/sshconn.py"}], "after_files": [{"content": "import paramiko\nimport requests.adapters\nimport six\nimport logging\nimport os\nimport signal\nimport socket\nimport subprocess\n\nfrom docker.transport.basehttpadapter import BaseHTTPAdapter\nfrom .. import constants\n\nif six.PY3:\n    import http.client as httplib\nelse:\n    import httplib\n\ntry:\n    import requests.packages.urllib3 as urllib3\nexcept ImportError:\n    import urllib3\n\nRecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer\n\n\nclass SSHSocket(socket.socket):\n    def __init__(self, host):\n        super(SSHSocket, self).__init__(\n            socket.AF_INET, socket.SOCK_STREAM)\n        self.host = host\n        self.port = None\n        self.user = None\n        if ':' in self.host:\n            self.host, self.port = self.host.split(':')\n        if '@' in self.host:\n            self.user, self.host = self.host.split('@')\n\n        self.proc = None\n\n    def connect(self, **kwargs):\n        args = ['ssh']\n        if self.user:\n            args = args + ['-l', self.user]\n\n        if self.port:\n            args = args + ['-p', self.port]\n\n        args = args + ['--', self.host, 'docker system dial-stdio']\n\n        preexec_func = None\n        if not constants.IS_WINDOWS_PLATFORM:\n            def f():\n                signal.signal(signal.SIGINT, signal.SIG_IGN)\n            preexec_func = f\n\n        env = dict(os.environ)\n\n        # drop LD_LIBRARY_PATH and SSL_CERT_FILE\n        env.pop('LD_LIBRARY_PATH', None)\n        env.pop('SSL_CERT_FILE', None)\n\n        self.proc = subprocess.Popen(\n            ' '.join(args),\n            env=env,\n            shell=True,\n            stdout=subprocess.PIPE,\n            stdin=subprocess.PIPE,\n            preexec_fn=None if constants.IS_WINDOWS_PLATFORM else preexec_func)\n\n    def _write(self, data):\n        if not self.proc or self.proc.stdin.closed:\n            raise Exception('SSH subprocess not initiated.'\n                            'connect() must be called first.')\n        written = self.proc.stdin.write(data)\n        self.proc.stdin.flush()\n        return written\n\n    def sendall(self, data):\n        self._write(data)\n\n    def send(self, data):\n        return self._write(data)\n\n    def recv(self, n):\n        if not self.proc:\n            raise Exception('SSH subprocess not initiated.'\n                            'connect() must be called first.')\n        return self.proc.stdout.read(n)\n\n    def makefile(self, mode):\n        if not self.proc:\n            self.connect()\n        if six.PY3:\n            self.proc.stdout.channel = self\n\n        return self.proc.stdout\n\n    def close(self):\n        if not self.proc or self.proc.stdin.closed:\n            return\n        self.proc.stdin.write(b'\\n\\n')\n        self.proc.stdin.flush()\n        self.proc.terminate()\n\n\nclass SSHConnection(httplib.HTTPConnection, object):\n    def __init__(self, ssh_transport=None, timeout=60, host=None):\n        super(SSHConnection, self).__init__(\n            'localhost', timeout=timeout\n        )\n        self.ssh_transport = ssh_transport\n        self.timeout = timeout\n        self.ssh_host = host\n\n    def connect(self):\n        if self.ssh_transport:\n            sock = self.ssh_transport.open_session()\n            sock.settimeout(self.timeout)\n            sock.exec_command('docker system dial-stdio')\n        else:\n            sock = SSHSocket(self.ssh_host)\n            sock.settimeout(self.timeout)\n            sock.connect()\n\n        self.sock = sock\n\n\nclass SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):\n    scheme = 'ssh'\n\n    def __init__(self, ssh_client=None, timeout=60, maxsize=10, host=None):\n        super(SSHConnectionPool, self).__init__(\n            'localhost', timeout=timeout, maxsize=maxsize\n        )\n        self.ssh_transport = None\n        self.timeout = timeout\n        if ssh_client:\n            self.ssh_transport = ssh_client.get_transport()\n        self.ssh_host = host\n\n    def _new_conn(self):\n        return SSHConnection(self.ssh_transport, self.timeout, self.ssh_host)\n\n    # When re-using connections, urllib3 calls fileno() on our\n    # SSH channel instance, quickly overloading our fd limit. To avoid this,\n    # we override _get_conn\n    def _get_conn(self, timeout):\n        conn = None\n        try:\n            conn = self.pool.get(block=self.block, timeout=timeout)\n\n        except AttributeError:  # self.pool is None\n            raise urllib3.exceptions.ClosedPoolError(self, \"Pool is closed.\")\n\n        except six.moves.queue.Empty:\n            if self.block:\n                raise urllib3.exceptions.EmptyPoolError(\n                    self,\n                    \"Pool reached maximum size and no more \"\n                    \"connections are allowed.\"\n                )\n            pass  # Oh well, we'll create a new connection then\n\n        return conn or self._new_conn()\n\n\nclass SSHHTTPAdapter(BaseHTTPAdapter):\n\n    __attrs__ = requests.adapters.HTTPAdapter.__attrs__ + [\n        'pools', 'timeout', 'ssh_client', 'ssh_params', 'max_pool_size'\n    ]\n\n    def __init__(self, base_url, timeout=60,\n                 pool_connections=constants.DEFAULT_NUM_POOLS,\n                 max_pool_size=constants.DEFAULT_MAX_POOL_SIZE,\n                 shell_out=False):\n        self.ssh_client = None\n        if not shell_out:\n            self._create_paramiko_client(base_url)\n            self._connect()\n\n        self.ssh_host = base_url\n        if base_url.startswith('ssh://'):\n            self.ssh_host = base_url[len('ssh://'):]\n\n        self.timeout = timeout\n        self.max_pool_size = max_pool_size\n        self.pools = RecentlyUsedContainer(\n            pool_connections, dispose_func=lambda p: p.close()\n        )\n        super(SSHHTTPAdapter, self).__init__()\n\n    def _create_paramiko_client(self, base_url):\n        logging.getLogger(\"paramiko\").setLevel(logging.WARNING)\n        self.ssh_client = paramiko.SSHClient()\n        base_url = six.moves.urllib_parse.urlparse(base_url)\n        self.ssh_params = {\n            \"hostname\": base_url.hostname,\n            \"port\": base_url.port,\n            \"username\": base_url.username\n            }\n        ssh_config_file = os.path.expanduser(\"~/.ssh/config\")\n        if os.path.exists(ssh_config_file):\n            conf = paramiko.SSHConfig()\n            with open(ssh_config_file) as f:\n                conf.parse(f)\n            host_config = conf.lookup(base_url.hostname)\n            if 'proxycommand' in host_config:\n                self.ssh_params[\"sock\"] = paramiko.ProxyCommand(\n                    self.ssh_conf['proxycommand']\n                )\n            if 'hostname' in host_config:\n                self.ssh_params['hostname'] = host_config['hostname']\n            if base_url.port is None and 'port' in host_config:\n                self.ssh_params['port'] = host_config['port']\n            if base_url.username is None and 'user' in host_config:\n                self.ssh_params['username'] = host_config['user']\n            if 'identityfile' in host_config:\n                self.ssh_params['key_filename'] = host_config['identityfile']\n\n        self.ssh_client.load_system_host_keys()\n        self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())\n\n    def _connect(self):\n        if self.ssh_client:\n            self.ssh_client.connect(**self.ssh_params)\n\n    def get_connection(self, url, proxies=None):\n        if not self.ssh_client:\n            return SSHConnectionPool(\n                ssh_client=self.ssh_client,\n                timeout=self.timeout,\n                maxsize=self.max_pool_size,\n                host=self.ssh_host\n            )\n        with self.pools.lock:\n            pool = self.pools.get(url)\n            if pool:\n                return pool\n\n            # Connection is closed try a reconnect\n            if self.ssh_client and not self.ssh_client.get_transport():\n                self._connect()\n\n            pool = SSHConnectionPool(\n                ssh_client=self.ssh_client,\n                timeout=self.timeout,\n                maxsize=self.max_pool_size,\n                host=self.ssh_host\n            )\n            self.pools[url] = pool\n\n        return pool\n\n    def close(self):\n        super(SSHHTTPAdapter, self).close()\n        if self.ssh_client:\n            self.ssh_client.close()\n", "path": "docker/transport/sshconn.py"}]}