1010# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1111# License for the specific language governing permissions and limitations
1212# under the License.
13+ import contextlib
1314import functools as ft
1415import importlib .metadata
1516import ipaddress
1617import os
18+ import socket
1719import urllib
1820import urllib .parse
1921from collections .abc import Iterable
2426from docker .models .images import Image , ImageCollection
2527from typing_extensions import ParamSpec
2628
29+ from testcontainers .core import utils
2730from testcontainers .core .auth import DockerAuthInfo , parse_docker_auth_config
31+ from testcontainers .core .config import ConnectionMode
2832from testcontainers .core .config import testcontainers_config as c
2933from testcontainers .core .labels import SESSION_ID , create_labels
30- from testcontainers .core .utils import default_gateway_ip , inside_container , setup_logger
3134
32- LOGGER = setup_logger (__name__ )
35+ LOGGER = utils . setup_logger (__name__ )
3336
3437_P = ParamSpec ("_P" )
3538_T = TypeVar ("_T" )
@@ -127,8 +130,18 @@ def find_host_network(self) -> Optional[str]:
127130 """
128131 # If we're docker in docker running on a custom network, we need to inherit the
129132 # 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
130142 try :
131- docker_host = ipaddress .IPv4Address (self .host ())
143+ host_ip = socket .gethostbyname (self .host ())
144+ docker_host = ipaddress .IPv4Address (host_ip )
132145 # See if we can find the host on our networks
133146 for network in self .client .networks .list (filters = {"type" : "custom" }):
134147 if "IPAM" in network .attrs :
@@ -139,7 +152,7 @@ def find_host_network(self) -> Optional[str]:
139152 continue
140153 if docker_host in subnet :
141154 return network .name
142- except ipaddress .AddressValueError :
155+ except ( ipaddress .AddressValueError , OSError ) :
143156 pass
144157 return None
145158
@@ -187,6 +200,28 @@ def gateway_ip(self, container_id: str) -> str:
187200 network_name = self .network_name (container_id )
188201 return container ["NetworkSettings" ]["Networks" ][network_name ]["Gateway" ]
189202
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+
190225 def host (self ) -> str :
191226 """
192227 Get the hostname or ip address of the docker host.
@@ -196,13 +231,15 @@ def host(self) -> str:
196231 return host
197232 try :
198233 url = urllib .parse .urlparse (self .client .api .base_url )
199-
200234 except ValueError :
201235 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"
203240 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 ()
206243 if ip_address :
207244 return ip_address
208245 return "localhost"
0 commit comments