Skip to content

Commit

Permalink
Use unix socket proxy on OS X instead of netty KQueue route (#410)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rnorth authored Jul 24, 2017
1 parent d7710b9 commit 51d1d45
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.

## UNRELEASED
### Fixed
- 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)

### Changed
- Removed Guava usage from `jdbc` module (#401)
Expand Down
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
<version>2.0.1</version>
</dependency>

<dependency>
<groupId>org.rnorth</groupId>
<artifactId>tcp-unix-socket-proxy</artifactId>
<version>1.0.1</version>
</dependency>

<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-exec</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class DockerClientFactory {
private static final List<DockerClientProviderStrategy> CONFIGURATION_STRATEGIES =
asList(new EnvironmentAndSystemPropertyClientProviderStrategy(),
new UnixSocketClientProviderStrategy(),
new ProxiedUnixSocketClientProviderStrategy(),
new DockerMachineClientProviderStrategy(),
new WindowsClientProviderStrategy());
private String activeApiVersion;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testcontainers.containers.wait;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.SystemUtils;
import org.rnorth.ducttape.TimeoutException;
import org.rnorth.ducttape.unreliables.Unreliables;
import org.testcontainers.DockerClientFactory;
Expand Down Expand Up @@ -93,8 +94,8 @@ protected void waitUntilReady() {

private boolean shouldCheckWithCommand() {
// Special case for Docker for Mac, see #160
if(!DockerClientFactory.instance().isUsing(DockerMachineClientProviderStrategy.class)
&& System.getProperty("os.name").toLowerCase().contains("mac")) {
if (! DockerClientFactory.instance().isUsing(DockerMachineClientProviderStrategy.class) &&
SystemUtils.IS_OS_MAC_OSX) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,14 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List<DockerClie
try {
Class<? extends DockerClientProviderStrategy> strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it);
return Stream.of(strategyClass.newInstance());
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
LOGGER.warn("Can't instantiate a strategy from " + it, e);
} catch (ClassNotFoundException e) {
LOGGER.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " +
"This probably means that cached configuration refers to a client provider " +
"class that is not available in this version of Testcontainers. Other " +
"strategies will be tried instead.", it);
return Stream.empty();
} catch (InstantiationException | IllegalAccessException e) {
LOGGER.warn("Can't instantiate a strategy from {}", it, e);
return Stream.empty();
}
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
*/
@Slf4j
public class DockerMachineClientProviderStrategy extends DockerClientProviderStrategy {

public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10;

private static final String PING_TIMEOUT_DEFAULT = "30";
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.dockermachineprovider.timeout";

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

@Override
protected int getPriority() {
return PRIORITY;
return ProxiedUnixSocketClientProviderStrategy.PRIORITY - 10;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@Slf4j
public class EnvironmentAndSystemPropertyClientProviderStrategy extends DockerClientProviderStrategy {

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

private static final String PING_TIMEOUT_DEFAULT = "10";
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.environmentprovider.timeout";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.testcontainers.dockerclient;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.SystemUtils;
import org.rnorth.tcpunixsocketproxy.TcpToUnixSocketProxy;
import org.testcontainers.utility.ComparableVersion;

import java.io.File;

@Slf4j
public class ProxiedUnixSocketClientProviderStrategy extends UnixSocketClientProviderStrategy {

public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10;

private final File socketFile = new File(DOCKER_SOCK_PATH);

@Override
protected boolean isApplicable() {
final boolean nettyDoesNotSupportMacUnixSockets = SystemUtils.IS_OS_MAC_OSX &&
ComparableVersion.OS_VERSION.isLessThan("10.12");

return nettyDoesNotSupportMacUnixSockets && socketFile.exists();
}

@Override
protected int getPriority() {
return PRIORITY;
}

@Override
public void test() throws InvalidConfigurationException {
TcpToUnixSocketProxy proxy = new TcpToUnixSocketProxy(socketFile);

try {
int proxyPort = proxy.start().getPort();

config = tryConfiguration("tcp://localhost:" + proxyPort);

log.debug("Accessing unix domain socket via TCP proxy (" + DOCKER_SOCK_PATH + " via localhost:" + proxyPort + ")");
} catch (Exception e) {

proxy.stop();

throw new InvalidConfigurationException("ping failed", e);
}

}

@Override
public String getDescription() {
return "local Unix socket (via TCP proxy)";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,29 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.SystemUtils;
import org.jetbrains.annotations.NotNull;
import org.testcontainers.utility.ComparableVersion;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Slf4j
public class UnixSocketClientProviderStrategy extends DockerClientProviderStrategy {

public static final int PRIORITY = 100;

protected static final String DOCKER_SOCK_PATH = "/var/run/docker.sock";
private static final String SOCKET_LOCATION = "unix://" + DOCKER_SOCK_PATH;
private static final int SOCKET_FILE_MODE_MASK = 0xc000;
private static final String PING_TIMEOUT_DEFAULT = "10";
private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.unixsocketprovider.timeout";

public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20;

@Override
protected boolean isApplicable() {
return SystemUtils.IS_OS_UNIX && new File(DOCKER_SOCK_PATH).exists();
}
final boolean nettyDoesSupportMacUnixSockets = SystemUtils.IS_OS_MAC_OSX &&
ComparableVersion.OS_VERSION.isGreaterThanOrEqualTo("10.12");

@Override
protected int getPriority() {
return PRIORITY;
return SystemUtils.IS_OS_LINUX || nettyDoesSupportMacUnixSockets;
}

@Override
Expand Down Expand Up @@ -75,4 +72,8 @@ public String getDescription() {
return "local Unix socket (" + SOCKET_LOCATION + ")";
}

@Override
protected int getPriority() {
return PRIORITY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class ComparableVersion implements Comparable<ComparableVersion> {

private final String[] parts;

public static final ComparableVersion OS_VERSION = new ComparableVersion(System.getProperty("os.version"));

public ComparableVersion(String version) {
this.parts = version.split("\\.");
}
Expand All @@ -24,4 +26,12 @@ public int compareTo(@NotNull ComparableVersion other) {

return 0;
}

public boolean isLessThan(String other) {
return this.compareTo(new ComparableVersion(other)) < 0;
}

public boolean isGreaterThanOrEqualTo(String other) {
return this.compareTo(new ComparableVersion(other)) >= 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.testcontainers;

import org.assertj.core.api.ListAssert;
import org.junit.*;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;
Expand Down

0 comments on commit 51d1d45

Please sign in to comment.