Skip to content

Commit 8712606

Browse files
authored
Test DOCKER_HOST in DockerClientProviderStrategy (#5357)
* Test `DOCKER_HOST` in `DockerClientProviderStrategy` * Update DockerClientProviderStrategy.java
1 parent d4e7671 commit 8712606

File tree

1 file changed

+88
-13
lines changed

1 file changed

+88
-13
lines changed

core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,38 @@
77
import com.github.dockerjava.core.DockerClientImpl;
88
import com.github.dockerjava.core.RemoteApiVersion;
99
import com.github.dockerjava.transport.DockerHttpClient;
10+
import com.github.dockerjava.transport.NamedPipeSocket;
11+
import com.github.dockerjava.transport.SSLConfig;
12+
import com.github.dockerjava.transport.UnixSocket;
1013
import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
1114
import com.google.common.annotations.VisibleForTesting;
1215
import com.google.common.base.Throwables;
1316
import lombok.Getter;
1417
import lombok.extern.slf4j.Slf4j;
1518
import org.apache.commons.io.IOUtils;
1619
import org.apache.commons.lang3.StringUtils;
20+
import org.awaitility.Awaitility;
1721
import org.jetbrains.annotations.Nullable;
1822
import org.rnorth.ducttape.TimeoutException;
1923
import org.rnorth.ducttape.ratelimits.RateLimiter;
2024
import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
2125
import org.rnorth.ducttape.unreliables.Unreliables;
2226
import org.testcontainers.DockerClientFactory;
27+
import org.testcontainers.UnstableAPI;
2328
import org.testcontainers.utility.TestcontainersConfiguration;
2429

30+
import javax.net.SocketFactory;
31+
import java.io.File;
32+
import java.net.InetSocketAddress;
33+
import java.net.Socket;
34+
import java.net.SocketAddress;
35+
import java.net.SocketTimeoutException;
2536
import java.net.URI;
37+
import java.security.KeyManagementException;
38+
import java.security.KeyStoreException;
39+
import java.security.NoSuchAlgorithmException;
40+
import java.security.UnrecoverableKeyException;
41+
import java.time.Duration;
2642
import java.util.ArrayList;
2743
import java.util.Collections;
2844
import java.util.Comparator;
@@ -31,6 +47,7 @@
3147
import java.util.Objects;
3248
import java.util.Optional;
3349
import java.util.Set;
50+
import java.util.concurrent.Callable;
3451
import java.util.concurrent.TimeUnit;
3552
import java.util.concurrent.atomic.AtomicBoolean;
3653
import java.util.function.Predicate;
@@ -104,6 +121,71 @@ public DockerClient getClient() {
104121
return dockerClient;
105122
}
106123

124+
/**
125+
* TODO we should consider moving this to docker-java at some point
126+
*/
127+
@UnstableAPI
128+
protected boolean test() {
129+
TransportConfig transportConfig = getTransportConfig();
130+
URI dockerHost = transportConfig.getDockerHost();
131+
132+
Callable<Socket> socketProvider;
133+
SocketAddress socketAddress;
134+
switch (dockerHost.getScheme()) {
135+
case "tcp":
136+
case "http":
137+
case "https":
138+
SocketFactory socketFactory = SocketFactory.getDefault();
139+
SSLConfig sslConfig = transportConfig.getSslConfig();
140+
if (sslConfig != null) {
141+
try {
142+
socketFactory = sslConfig.getSSLContext().getSocketFactory();
143+
} catch (KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) {
144+
log.warn("Exception while creating SSLSocketFactory", e);
145+
return false;
146+
}
147+
}
148+
socketProvider = socketFactory::createSocket;
149+
socketAddress = new InetSocketAddress(dockerHost.getHost(), dockerHost.getPort());
150+
break;
151+
case "unix":
152+
case "npipe":
153+
if (!new File(dockerHost.getPath()).exists()) {
154+
log.debug("DOCKER_HOST socket file '{}' does not exist", dockerHost.getPath());
155+
return false;
156+
}
157+
socketProvider = () -> {
158+
switch (dockerHost.getScheme()) {
159+
case "unix":
160+
return UnixSocket.get(dockerHost.getPath());
161+
case "npipe":
162+
return new NamedPipeSocket(dockerHost.getPath());
163+
default:
164+
throw new IllegalStateException("Unexpected scheme " + dockerHost.getScheme());
165+
}
166+
};
167+
socketAddress = new InetSocketAddress("localhost", 2375);
168+
break;
169+
default:
170+
log.warn("Unknown DOCKER_HOST scheme {}, skipping the strategy test...", dockerHost.getScheme());
171+
return true;
172+
}
173+
174+
try (Socket socket = socketProvider.call()) {
175+
Duration timeout = Duration.ofMillis(200);
176+
Awaitility.await()
177+
.atMost(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS)
178+
.pollInterval(timeout)
179+
.pollDelay(Duration.ofSeconds(0)) // start checking immediately
180+
.ignoreExceptionsInstanceOf(SocketTimeoutException.class)
181+
.untilAsserted(() -> socket.connect(socketAddress, (int) timeout.toMillis()));
182+
return true;
183+
} catch (Exception e) {
184+
log.warn("DOCKER_HOST {} is not listening", dockerHost);
185+
return false;
186+
}
187+
}
188+
107189
/**
108190
* Determine the right DockerClientConfig to use for building clients by trial-and-error.
109191
*
@@ -161,20 +243,13 @@ public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) {
161243
private static boolean tryOutStrategy(List<String> configurationFailures, DockerClientProviderStrategy strategy) {
162244
try {
163245
log.debug("Trying out strategy: {}", strategy.getClass().getSimpleName());
164-
DockerClient dockerClient = strategy.getDockerClient();
165-
166-
Info info;
167-
try {
168-
info = Unreliables.retryUntilSuccess(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS, () -> {
169-
return strategy.PING_RATE_LIMITER.getWhenReady(() -> {
170-
log.debug("Pinging docker daemon...");
171-
return dockerClient.infoCmd().exec();
172-
});
173-
});
174-
} catch (TimeoutException e) {
175-
IOUtils.closeQuietly(dockerClient);
176-
throw e;
246+
247+
if (!strategy.test()) {
248+
log.debug("strategy {} did not pass the test", strategy.getClass().getSimpleName());
249+
return false;
177250
}
251+
252+
Info info = strategy.getDockerClient().infoCmd().exec();
178253
log.info("Found Docker environment with {}", strategy.getDescription());
179254
log.debug(
180255
"Transport type: '{}', Docker host: '{}'",

0 commit comments

Comments
 (0)