Skip to content

Commit 51d1d45

Browse files
authored
Use unix socket proxy on OS X instead of netty KQueue route (#410)
Adjust docker client provider strategies so that a proxied (TCP) connection is used to connect to the Docker daemon on < OS X 10.12. Fixes #402.
1 parent d7710b9 commit 51d1d45

File tree

11 files changed

+98
-19
lines changed

11 files changed

+98
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
33

44
## UNRELEASED
55
### Fixed
6+
- Worked around incompatibility between Netty's Unix socket support and OS X 10.11. Reinstated use of TCP-Unix Socket proxy when running on OS X prior to v10.12. (Fixes #402)
67

78
### Changed
89
- Removed Guava usage from `jdbc` module (#401)

core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@
6868
<version>2.0.1</version>
6969
</dependency>
7070

71+
<dependency>
72+
<groupId>org.rnorth</groupId>
73+
<artifactId>tcp-unix-socket-proxy</artifactId>
74+
<version>1.0.1</version>
75+
</dependency>
76+
7177
<dependency>
7278
<groupId>org.zeroturnaround</groupId>
7379
<artifactId>zt-exec</artifactId>

core/src/main/java/org/testcontainers/DockerClientFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public class DockerClientFactory {
5050
private static final List<DockerClientProviderStrategy> CONFIGURATION_STRATEGIES =
5151
asList(new EnvironmentAndSystemPropertyClientProviderStrategy(),
5252
new UnixSocketClientProviderStrategy(),
53+
new ProxiedUnixSocketClientProviderStrategy(),
5354
new DockerMachineClientProviderStrategy(),
5455
new WindowsClientProviderStrategy());
5556
private String activeApiVersion;

core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.testcontainers.containers.wait;
22

33
import lombok.extern.slf4j.Slf4j;
4+
import org.apache.commons.lang.SystemUtils;
45
import org.rnorth.ducttape.TimeoutException;
56
import org.rnorth.ducttape.unreliables.Unreliables;
67
import org.testcontainers.DockerClientFactory;
@@ -93,8 +94,8 @@ protected void waitUntilReady() {
9394

9495
private boolean shouldCheckWithCommand() {
9596
// Special case for Docker for Mac, see #160
96-
if(!DockerClientFactory.instance().isUsing(DockerMachineClientProviderStrategy.class)
97-
&& System.getProperty("os.name").toLowerCase().contains("mac")) {
97+
if (! DockerClientFactory.instance().isUsing(DockerMachineClientProviderStrategy.class) &&
98+
SystemUtils.IS_OS_MAC_OSX) {
9899
return true;
99100
}
100101

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,14 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List<DockerClie
7575
try {
7676
Class<? extends DockerClientProviderStrategy> strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it);
7777
return Stream.of(strategyClass.newInstance());
78-
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
79-
LOGGER.warn("Can't instantiate a strategy from " + it, e);
78+
} catch (ClassNotFoundException e) {
79+
LOGGER.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " +
80+
"This probably means that cached configuration refers to a client provider " +
81+
"class that is not available in this version of Testcontainers. Other " +
82+
"strategies will be tried instead.", it);
83+
return Stream.empty();
84+
} catch (InstantiationException | IllegalAccessException e) {
85+
LOGGER.warn("Can't instantiate a strategy from {}", it, e);
8086
return Stream.empty();
8187
}
8288
}),

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
*/
1717
@Slf4j
1818
public class DockerMachineClientProviderStrategy extends DockerClientProviderStrategy {
19-
20-
public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10;
21-
2219
private static final String PING_TIMEOUT_DEFAULT = "30";
2320
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.dockermachineprovider.timeout";
2421

@@ -29,7 +26,7 @@ protected boolean isApplicable() {
2926

3027
@Override
3128
protected int getPriority() {
32-
return PRIORITY;
29+
return ProxiedUnixSocketClientProviderStrategy.PRIORITY - 10;
3330
}
3431

3532
@Override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
@Slf4j
1313
public class EnvironmentAndSystemPropertyClientProviderStrategy extends DockerClientProviderStrategy {
1414

15-
public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY - 10;
15+
public static final int PRIORITY = 100;
1616

1717
private static final String PING_TIMEOUT_DEFAULT = "10";
1818
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.environmentprovider.timeout";
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.testcontainers.dockerclient;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.apache.commons.lang.SystemUtils;
5+
import org.rnorth.tcpunixsocketproxy.TcpToUnixSocketProxy;
6+
import org.testcontainers.utility.ComparableVersion;
7+
8+
import java.io.File;
9+
10+
@Slf4j
11+
public class ProxiedUnixSocketClientProviderStrategy extends UnixSocketClientProviderStrategy {
12+
13+
public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10;
14+
15+
private final File socketFile = new File(DOCKER_SOCK_PATH);
16+
17+
@Override
18+
protected boolean isApplicable() {
19+
final boolean nettyDoesNotSupportMacUnixSockets = SystemUtils.IS_OS_MAC_OSX &&
20+
ComparableVersion.OS_VERSION.isLessThan("10.12");
21+
22+
return nettyDoesNotSupportMacUnixSockets && socketFile.exists();
23+
}
24+
25+
@Override
26+
protected int getPriority() {
27+
return PRIORITY;
28+
}
29+
30+
@Override
31+
public void test() throws InvalidConfigurationException {
32+
TcpToUnixSocketProxy proxy = new TcpToUnixSocketProxy(socketFile);
33+
34+
try {
35+
int proxyPort = proxy.start().getPort();
36+
37+
config = tryConfiguration("tcp://localhost:" + proxyPort);
38+
39+
log.debug("Accessing unix domain socket via TCP proxy (" + DOCKER_SOCK_PATH + " via localhost:" + proxyPort + ")");
40+
} catch (Exception e) {
41+
42+
proxy.stop();
43+
44+
throw new InvalidConfigurationException("ping failed", e);
45+
}
46+
47+
}
48+
49+
@Override
50+
public String getDescription() {
51+
return "local Unix socket (via TCP proxy)";
52+
}
53+
54+
}

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,29 @@
55
import lombok.extern.slf4j.Slf4j;
66
import org.apache.commons.lang.SystemUtils;
77
import org.jetbrains.annotations.NotNull;
8+
import org.testcontainers.utility.ComparableVersion;
89

9-
import java.io.File;
1010
import java.io.IOException;
1111
import java.nio.file.Files;
1212
import java.nio.file.Path;
1313
import java.nio.file.Paths;
1414

1515
@Slf4j
1616
public class UnixSocketClientProviderStrategy extends DockerClientProviderStrategy {
17-
18-
public static final int PRIORITY = 100;
19-
2017
protected static final String DOCKER_SOCK_PATH = "/var/run/docker.sock";
2118
private static final String SOCKET_LOCATION = "unix://" + DOCKER_SOCK_PATH;
2219
private static final int SOCKET_FILE_MODE_MASK = 0xc000;
2320
private static final String PING_TIMEOUT_DEFAULT = "10";
2421
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.unixsocketprovider.timeout";
2522

23+
public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20;
24+
2625
@Override
2726
protected boolean isApplicable() {
28-
return SystemUtils.IS_OS_UNIX && new File(DOCKER_SOCK_PATH).exists();
29-
}
27+
final boolean nettyDoesSupportMacUnixSockets = SystemUtils.IS_OS_MAC_OSX &&
28+
ComparableVersion.OS_VERSION.isGreaterThanOrEqualTo("10.12");
3029

31-
@Override
32-
protected int getPriority() {
33-
return PRIORITY;
30+
return SystemUtils.IS_OS_LINUX || nettyDoesSupportMacUnixSockets;
3431
}
3532

3633
@Override
@@ -75,4 +72,8 @@ public String getDescription() {
7572
return "local Unix socket (" + SOCKET_LOCATION + ")";
7673
}
7774

75+
@Override
76+
protected int getPriority() {
77+
return PRIORITY;
78+
}
7879
}

core/src/main/java/org/testcontainers/utility/ComparableVersion.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
66

77
private final String[] parts;
88

9+
public static final ComparableVersion OS_VERSION = new ComparableVersion(System.getProperty("os.version"));
10+
911
public ComparableVersion(String version) {
1012
this.parts = version.split("\\.");
1113
}
@@ -24,4 +26,12 @@ public int compareTo(@NotNull ComparableVersion other) {
2426

2527
return 0;
2628
}
29+
30+
public boolean isLessThan(String other) {
31+
return this.compareTo(new ComparableVersion(other)) < 0;
32+
}
33+
34+
public boolean isGreaterThanOrEqualTo(String other) {
35+
return this.compareTo(new ComparableVersion(other)) >= 0;
36+
}
2737
}

0 commit comments

Comments
 (0)