10
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
11
# License for the specific language governing permissions and limitations
12
12
# under the License.
13
+ import contextlib
13
14
import functools as ft
14
15
import importlib .metadata
15
16
import ipaddress
16
17
import os
18
+ import socket
17
19
import urllib
18
20
import urllib .parse
19
21
from collections .abc import Iterable
24
26
from docker .models .images import Image , ImageCollection
25
27
from typing_extensions import ParamSpec
26
28
29
+ from testcontainers .core import utils
27
30
from testcontainers .core .auth import DockerAuthInfo , parse_docker_auth_config
31
+ from testcontainers .core .config import ConnectionMode
28
32
from testcontainers .core .config import testcontainers_config as c
29
33
from testcontainers .core .labels import SESSION_ID , create_labels
30
- from testcontainers .core .utils import default_gateway_ip , inside_container , setup_logger
31
34
32
- LOGGER = setup_logger (__name__ )
35
+ LOGGER = utils . setup_logger (__name__ )
33
36
34
37
_P = ParamSpec ("_P" )
35
38
_T = TypeVar ("_T" )
@@ -127,8 +130,18 @@ def find_host_network(self) -> Optional[str]:
127
130
"""
128
131
# If we're docker in docker running on a custom network, we need to inherit the
129
132
# network settings, so we can access the resulting container.
133
+
134
+ # first to try to find the network the container runs in, if we can determine
135
+ container_id = utils .get_running_in_container_id ()
136
+ if container_id :
137
+ with contextlib .suppress (Exception ):
138
+ return self .network_name (container_id )
139
+
140
+ # if this results nothing, try to determine the network based on the
141
+ # docker_host
130
142
try :
131
- docker_host = ipaddress .IPv4Address (self .host ())
143
+ host_ip = socket .gethostbyname (self .host ())
144
+ docker_host = ipaddress .IPv4Address (host_ip )
132
145
# See if we can find the host on our networks
133
146
for network in self .client .networks .list (filters = {"type" : "custom" }):
134
147
if "IPAM" in network .attrs :
@@ -139,7 +152,7 @@ def find_host_network(self) -> Optional[str]:
139
152
continue
140
153
if docker_host in subnet :
141
154
return network .name
142
- except ipaddress .AddressValueError :
155
+ except ( ipaddress .AddressValueError , OSError ) :
143
156
pass
144
157
return None
145
158
@@ -187,6 +200,28 @@ def gateway_ip(self, container_id: str) -> str:
187
200
network_name = self .network_name (container_id )
188
201
return container ["NetworkSettings" ]["Networks" ][network_name ]["Gateway" ]
189
202
203
+ def get_connection_mode (self ) -> ConnectionMode :
204
+ """
205
+ Determine the connection mode.
206
+
207
+ See https://github.com/testcontainers/testcontainers-python/issues/475#issuecomment-2407250970
208
+ """
209
+ if c .connection_mode_override :
210
+ return c .connection_mode_override
211
+ localhosts = {"localhost" , "127.0.0.1" , "::1" }
212
+ if not utils .inside_container () or self .host () not in localhosts :
213
+ # if running not inside a container or with a non-local docker client,
214
+ # connect ot the docker host per default
215
+ return ConnectionMode .docker_host
216
+ elif self .find_host_network ():
217
+ # a host network could be determined, indicator for DooD,
218
+ # so we should connect to the bridge_ip as the container we run in
219
+ # and the one we started are connected to the same network
220
+ # that might have no access to either docker_host or the gateway
221
+ return ConnectionMode .bridge_ip
222
+ # default for DinD
223
+ return ConnectionMode .gateway_ip
224
+
190
225
def host (self ) -> str :
191
226
"""
192
227
Get the hostname or ip address of the docker host.
@@ -196,13 +231,15 @@ def host(self) -> str:
196
231
return host
197
232
try :
198
233
url = urllib .parse .urlparse (self .client .api .base_url )
199
-
200
234
except ValueError :
201
235
return "localhost"
202
- if "http" in url .scheme or "tcp" in url .scheme :
236
+ if "http" in url .scheme or "tcp" in url .scheme and url .hostname :
237
+ # see https://github.com/testcontainers/testcontainers-python/issues/415
238
+ if url .hostname == "localnpipe" and utils .is_windows ():
239
+ return "localhost"
203
240
return url .hostname
204
- if inside_container () and ("unix" in url .scheme or "npipe" in url .scheme ):
205
- ip_address = default_gateway_ip ()
241
+ if utils . inside_container () and ("unix" in url .scheme or "npipe" in url .scheme ):
242
+ ip_address = utils . default_gateway_ip ()
206
243
if ip_address :
207
244
return ip_address
208
245
return "localhost"
0 commit comments