prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Support OpenSSH's IdentityFile config option
  # Description
  As a developer I want `docker-py` to load the identity file according to my setting specified in `~/.ssh/config`, not only the "default" `id_rsa` file.
  
  # Example
  I have a `~/.ssh/config` file with contents:
  ```ssh
  Host myHost
      User myUser
      HostName myIp
      IdentityFile C:/Users/me/.ssh/id_rsa_custom_file
      IdentitiesOnly yes
  ```
  
  Now I would like `docker-py` to pick up `C:/Users/me/.ssh/id_rsa_custom_file` for trying to connect to the remote host (For example when I want to run `docker-compose -H "ssh://myHost" ps`. However right now it does not.
  
  When I rename `C:/Users/me/.ssh/id_rsa_custom_file` to `C:/Users/me/.ssh/id_rsa` it works just fine. However this is not an option for me since I have multiple identity files and hosts that I want to use.
  
  # Proposal
  Add something like this to the [`sshcon.py`](https://github.com/docker/docker-py/blob/c285bee1bc59f6b2d65cee952b5522c88047a3bc/docker/transport/sshconn.py#L105):
  ```python
  if 'identityfile' in host_config:
      self.ssh_params['key_filename '] = host_config['identityfile']
  ```
  
  --- 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 requests.adapters
  3 import six
  4 import logging
  5 import os
  6 
  7 from docker.transport.basehttpadapter import BaseHTTPAdapter
  8 from .. import constants
  9 
  10 if six.PY3:
  11     import http.client as httplib
  12 else:
  13     import httplib
  14 
  15 try:
  16     import requests.packages.urllib3 as urllib3
  17 except ImportError:
  18     import urllib3
  19 
  20 RecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer
  21 
  22 
  23 class SSHConnection(httplib.HTTPConnection, object):
  24     def __init__(self, ssh_transport, timeout=60):
  25         super(SSHConnection, self).__init__(
  26             'localhost', timeout=timeout
  27         )
  28         self.ssh_transport = ssh_transport
  29         self.timeout = timeout
  30 
  31     def connect(self):
  32         sock = self.ssh_transport.open_session()
  33         sock.settimeout(self.timeout)
  34         sock.exec_command('docker system dial-stdio')
  35         self.sock = sock
  36 
  37 
  38 class SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):
  39     scheme = 'ssh'
  40 
  41     def __init__(self, ssh_client, timeout=60, maxsize=10):
  42         super(SSHConnectionPool, self).__init__(
  43             'localhost', timeout=timeout, maxsize=maxsize
  44         )
  45         self.ssh_transport = ssh_client.get_transport()
  46         self.timeout = timeout
  47 
  48     def _new_conn(self):
  49         return SSHConnection(self.ssh_transport, self.timeout)
  50 
  51     # When re-using connections, urllib3 calls fileno() on our
  52     # SSH channel instance, quickly overloading our fd limit. To avoid this,
  53     # we override _get_conn
  54     def _get_conn(self, timeout):
  55         conn = None
  56         try:
  57             conn = self.pool.get(block=self.block, timeout=timeout)
  58 
  59         except AttributeError:  # self.pool is None
  60             raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.")
  61 
  62         except six.moves.queue.Empty:
  63             if self.block:
  64                 raise urllib3.exceptions.EmptyPoolError(
  65                     self,
  66                     "Pool reached maximum size and no more "
  67                     "connections are allowed."
  68                 )
  69             pass  # Oh well, we'll create a new connection then
  70 
  71         return conn or self._new_conn()
  72 
  73 
  74 class SSHHTTPAdapter(BaseHTTPAdapter):
  75 
  76     __attrs__ = requests.adapters.HTTPAdapter.__attrs__ + [
  77         'pools', 'timeout', 'ssh_client', 'ssh_params'
  78     ]
  79 
  80     def __init__(self, base_url, timeout=60,
  81                  pool_connections=constants.DEFAULT_NUM_POOLS):
  82         logging.getLogger("paramiko").setLevel(logging.WARNING)
  83         self.ssh_client = paramiko.SSHClient()
  84         base_url = six.moves.urllib_parse.urlparse(base_url)
  85         self.ssh_params = {
  86             "hostname": base_url.hostname,
  87             "port": base_url.port,
  88             "username": base_url.username
  89             }
  90         ssh_config_file = os.path.expanduser("~/.ssh/config")
  91         if os.path.exists(ssh_config_file):
  92             conf = paramiko.SSHConfig()
  93             with open(ssh_config_file) as f:
  94                 conf.parse(f)
  95             host_config = conf.lookup(base_url.hostname)
  96             self.ssh_conf = host_config
  97             if 'proxycommand' in host_config:
  98                 self.ssh_params["sock"] = paramiko.ProxyCommand(
  99                     self.ssh_conf['proxycommand']
  100                 )
  101             if 'hostname' in host_config:
  102                 self.ssh_params['hostname'] = host_config['hostname']
  103             if base_url.port is None and 'port' in host_config:
  104                 self.ssh_params['port'] = self.ssh_conf['port']
  105             if base_url.username is None and 'user' in host_config:
  106                 self.ssh_params['username'] = self.ssh_conf['user']
  107 
  108         self.ssh_client.load_system_host_keys()
  109         self.ssh_client.set_missing_host_key_policy(paramiko.WarningPolicy())
  110 
  111         self._connect()
  112         self.timeout = timeout
  113         self.pools = RecentlyUsedContainer(
  114             pool_connections, dispose_func=lambda p: p.close()
  115         )
  116         super(SSHHTTPAdapter, self).__init__()
  117 
  118     def _connect(self):
  119         self.ssh_client.connect(**self.ssh_params)
  120 
  121     def get_connection(self, url, proxies=None):
  122         with self.pools.lock:
  123             pool = self.pools.get(url)
  124             if pool:
  125                 return pool
  126 
  127             # Connection is closed try a reconnect
  128             if not self.ssh_client.get_transport():
  129                 self._connect()
  130 
  131             pool = SSHConnectionPool(
  132                 self.ssh_client, self.timeout
  133             )
  134             self.pools[url] = pool
  135 
  136         return pool
  137 
  138     def close(self):
  139         super(SSHHTTPAdapter, self).close()
  140         self.ssh_client.close()
  141
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/docker/transport/sshconn.py b/docker/transport/sshconn.py
  --- a/docker/transport/sshconn.py
  +++ b/docker/transport/sshconn.py
  @@ -100,6 +100,8 @@
                   )
               if 'hostname' in host_config:
                   self.ssh_params['hostname'] = host_config['hostname']
  +            if 'identityfile' in host_config:
  +                self.ssh_params['key_filename'] = host_config['identityfile']
               if base_url.port is None and 'port' in host_config:
                   self.ssh_params['port'] = self.ssh_conf['port']
               if base_url.username is None and 'user' in host_config:
  
verification_info: {"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@@ -100,6 +100,8 @@\n                 )\n             if 'hostname' in host_config:\n                 self.ssh_params['hostname'] = host_config['hostname']\n+            if 'identityfile' in host_config:\n+                self.ssh_params['key_filename'] = host_config['identityfile']\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", "issue": "Support OpenSSH's IdentityFile config option\n# Description\r\nAs a developer I want `docker-py` to load the identity file according to my setting specified in `~/.ssh/config`, not only the \"default\" `id_rsa` file.\r\n\r\n# Example\r\nI have a `~/.ssh/config` file with contents:\r\n```ssh\r\nHost myHost\r\n    User myUser\r\n    HostName myIp\r\n    IdentityFile C:/Users/me/.ssh/id_rsa_custom_file\r\n    IdentitiesOnly yes\r\n```\r\n\r\nNow I would like `docker-py` to pick up `C:/Users/me/.ssh/id_rsa_custom_file` for trying to connect to the remote host (For example when I want to run `docker-compose -H \"ssh://myHost\" ps`. However right now it does not.\r\n\r\nWhen I rename `C:/Users/me/.ssh/id_rsa_custom_file` to `C:/Users/me/.ssh/id_rsa` it works just fine. However this is not an option for me since I have multiple identity files and hosts that I want to use.\r\n\r\n# Proposal\r\nAdd something like this to the [`sshcon.py`](https://github.com/docker/docker-py/blob/c285bee1bc59f6b2d65cee952b5522c88047a3bc/docker/transport/sshconn.py#L105):\r\n```python\r\nif 'identityfile' in host_config:\r\n    self.ssh_params['key_filename '] = host_config['identityfile']\r\n```\n", "before_files": [{"content": "import paramiko\nimport requests.adapters\nimport six\nimport logging\nimport os\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 SSHConnection(httplib.HTTPConnection, object):\n    def __init__(self, ssh_transport, timeout=60):\n        super(SSHConnection, self).__init__(\n            'localhost', timeout=timeout\n        )\n        self.ssh_transport = ssh_transport\n        self.timeout = timeout\n\n    def connect(self):\n        sock = self.ssh_transport.open_session()\n        sock.settimeout(self.timeout)\n        sock.exec_command('docker system dial-stdio')\n        self.sock = sock\n\n\nclass SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):\n    scheme = 'ssh'\n\n    def __init__(self, ssh_client, timeout=60, maxsize=10):\n        super(SSHConnectionPool, self).__init__(\n            'localhost', timeout=timeout, maxsize=maxsize\n        )\n        self.ssh_transport = ssh_client.get_transport()\n        self.timeout = timeout\n\n    def _new_conn(self):\n        return SSHConnection(self.ssh_transport, self.timeout)\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'\n    ]\n\n    def __init__(self, base_url, timeout=60,\n                 pool_connections=constants.DEFAULT_NUM_POOLS):\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            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        self._connect()\n        self.timeout = timeout\n        self.pools = RecentlyUsedContainer(\n            pool_connections, dispose_func=lambda p: p.close()\n        )\n        super(SSHHTTPAdapter, self).__init__()\n\n    def _connect(self):\n        self.ssh_client.connect(**self.ssh_params)\n\n    def get_connection(self, url, proxies=None):\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 not self.ssh_client.get_transport():\n                self._connect()\n\n            pool = SSHConnectionPool(\n                self.ssh_client, self.timeout\n            )\n            self.pools[url] = pool\n\n        return pool\n\n    def close(self):\n        super(SSHHTTPAdapter, self).close()\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\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 SSHConnection(httplib.HTTPConnection, object):\n    def __init__(self, ssh_transport, timeout=60):\n        super(SSHConnection, self).__init__(\n            'localhost', timeout=timeout\n        )\n        self.ssh_transport = ssh_transport\n        self.timeout = timeout\n\n    def connect(self):\n        sock = self.ssh_transport.open_session()\n        sock.settimeout(self.timeout)\n        sock.exec_command('docker system dial-stdio')\n        self.sock = sock\n\n\nclass SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool):\n    scheme = 'ssh'\n\n    def __init__(self, ssh_client, timeout=60, maxsize=10):\n        super(SSHConnectionPool, self).__init__(\n            'localhost', timeout=timeout, maxsize=maxsize\n        )\n        self.ssh_transport = ssh_client.get_transport()\n        self.timeout = timeout\n\n    def _new_conn(self):\n        return SSHConnection(self.ssh_transport, self.timeout)\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'\n    ]\n\n    def __init__(self, base_url, timeout=60,\n                 pool_connections=constants.DEFAULT_NUM_POOLS):\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            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 'identityfile' in host_config:\n                self.ssh_params['key_filename'] = host_config['identityfile']\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        self._connect()\n        self.timeout = timeout\n        self.pools = RecentlyUsedContainer(\n            pool_connections, dispose_func=lambda p: p.close()\n        )\n        super(SSHHTTPAdapter, self).__init__()\n\n    def _connect(self):\n        self.ssh_client.connect(**self.ssh_params)\n\n    def get_connection(self, url, proxies=None):\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 not self.ssh_client.get_transport():\n                self._connect()\n\n            pool = SSHConnectionPool(\n                self.ssh_client, self.timeout\n            )\n            self.pools[url] = pool\n\n        return pool\n\n    def close(self):\n        super(SSHHTTPAdapter, self).close()\n        self.ssh_client.close()\n", "path": "docker/transport/sshconn.py"}]}