diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 73bf24e511c..77ae311bb47 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -158,9 +158,11 @@ public TransportConfig getTransportConfig() { @UnstableAPI public String getRemoteDockerUnixSocketPath() { - String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); - if (!StringUtils.isBlank(dockerSocketOverride)) { - return dockerSocketOverride; + if (this.strategy != null && this.strategy.allowUserOverrides()) { + String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); + if (!StringUtils.isBlank(dockerSocketOverride)) { + return dockerSocketOverride; + } } URI dockerHost = getTransportConfig().getDockerHost(); diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 01fb60e4b5d..8a959b443c8 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -57,6 +57,14 @@ /** * Mechanism to find a viable Docker client configuration according to the host system environment. + *

+ * The order is: + *

*/ @Slf4j public abstract class DockerClientProviderStrategy { @@ -90,6 +98,10 @@ protected boolean isPersistable() { return true; } + public boolean allowUserOverrides() { + return true; + } + /** * @return highest to lowest priority value */ @@ -217,7 +229,8 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List configurationFailures = new ArrayList<>(); List allStrategies = new ArrayList<>(); - // The environment has the highest priority + // Manually enforce priority independent of priority property of strategy + allStrategies.add(new TestcontainersHostPropertyClientProviderStrategy()); allStrategies.add(new EnvironmentAndSystemPropertyClientProviderStrategy()); // Next strategy to try out is the one configured using the Testcontainers configuration mechanism @@ -401,16 +414,23 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { public synchronized String getDockerHostIpAddress() { if (dockerHostIpAddress == null) { - dockerHostIpAddress = resolveDockerHostIpAddress(getDockerClient(), getTransportConfig().getDockerHost()); + dockerHostIpAddress = + resolveDockerHostIpAddress( + getDockerClient(), + getTransportConfig().getDockerHost(), + allowUserOverrides() + ); } return dockerHostIpAddress; } @VisibleForTesting - static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { - String hostOverride = System.getenv("TESTCONTAINERS_HOST_OVERRIDE"); - if (!StringUtils.isBlank(hostOverride)) { - return hostOverride; + static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost, boolean allowUserOverrides) { + if (allowUserOverrides) { + String hostOverride = System.getenv("TESTCONTAINERS_HOST_OVERRIDE"); + if (!StringUtils.isBlank(hostOverride)) { + return hostOverride; + } } switch (dockerHost.getScheme()) { diff --git a/core/src/main/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategy.java new file mode 100644 index 00000000000..39cd61c9c12 --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategy.java @@ -0,0 +1,63 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.util.Optional; + +/** + * Use tc.host in ~/.testcontainers.properties + * to try and locate a docker environment. + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +public final class TestcontainersHostPropertyClientProviderStrategy extends DockerClientProviderStrategy { + + public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10; + + private final DockerClientConfig dockerClientConfig; + + public TestcontainersHostPropertyClientProviderStrategy() { + this(DefaultDockerClientConfig.createDefaultConfigBuilder()); + } + + public TestcontainersHostPropertyClientProviderStrategy(DefaultDockerClientConfig.Builder configBuilder) { + Optional tcHost = Optional.ofNullable( + TestcontainersConfiguration.getInstance().getUserProperty("tc.host", null) + ); + + tcHost.ifPresent(configBuilder::withDockerHost); + this.dockerClientConfig = configBuilder.build(); + } + + @Override + public String getDescription() { + return "Testcontainers Host with tc.host=" + this.dockerClientConfig.getDockerHost(); + } + + @Override + public TransportConfig getTransportConfig() throws InvalidConfigurationException { + return TransportConfig + .builder() + .dockerHost(dockerClientConfig.getDockerHost()) + .sslConfig(dockerClientConfig.getSSLConfig()) + .build(); + } + + @Override + protected int getPriority() { + return PRIORITY; + } + + @Override + protected boolean isPersistable() { + return false; + } + + @Override + public boolean allowUserOverrides() { + return false; + } +} diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index f3bb8f8319a..44af923bb9a 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -279,18 +279,16 @@ public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nulla } /** - * Gets a configured setting from an environment variable. - *

- * Note that when searching environment variables, the prefix `TESTCONTAINERS_` will usually be applied to the - * property name, which will be converted to upper-case with underscore separators. This prefix will not be added - * if the property name begins `docker.`. + * Gets a configured setting from ~/.testcontainers.properties. * * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set */ @Contract("_, !null -> !null") public String getUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { - return getConfigurable(propertyName, defaultValue); + return this.userProperties.get(propertyName) != null + ? (String) this.userProperties.get(propertyName) + : defaultValue; } /** diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index d9cbad0ebff..62493d704a4 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -1,3 +1,4 @@ +org.testcontainers.dockerclient.TestcontainersHostPropertyClientProviderStrategy org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy org.testcontainers.dockerclient.UnixSocketClientProviderStrategy org.testcontainers.dockerclient.DockerMachineClientProviderStrategy diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index d14ffda42cc..757816cb189 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -19,7 +19,8 @@ public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( client, - URI.create("unix:///var/run/docker.sock") + URI.create("unix:///var/run/docker.sock"), + true ); assertThat(actual).isEqualTo("localhost"); } @@ -28,7 +29,8 @@ public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( client, - URI.create("http://12.23.34.45") + URI.create("http://12.23.34.45"), + true ); assertThat(actual).isEqualTo("12.23.34.45"); } @@ -37,7 +39,8 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( client, - URI.create("tcp://12.23.34.45") + URI.create("tcp://12.23.34.45"), + true ); assertThat(actual).isEqualTo("12.23.34.45"); } @@ -46,7 +49,8 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() { String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( client, - URI.create("gopher://12.23.34.45") + URI.create("gopher://12.23.34.45"), + true ); assertThat(actual).isNull(); } diff --git a/core/src/test/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategyTest.java new file mode 100644 index 00000000000..dba14e34b51 --- /dev/null +++ b/core/src/test/java/org/testcontainers/dockerclient/TestcontainersHostPropertyClientProviderStrategyTest.java @@ -0,0 +1,61 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.core.DefaultDockerClientConfig; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.testcontainers.utility.MockTestcontainersConfigurationRule; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.net.URI; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; + +@RunWith(MockitoJUnitRunner.class) +public class TestcontainersHostPropertyClientProviderStrategyTest { + + @Rule + public MockTestcontainersConfigurationRule mockConfig = new MockTestcontainersConfigurationRule(); + + private URI defaultDockerHost; + + private com.github.dockerjava.core.SSLConfig defaultSSLConfig; + + @Before + public void checkEnvironmentClear() { + // If docker-java picks up non-default settings from the environment, our test needs to know to expect those + DefaultDockerClientConfig defaultConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + this.defaultDockerHost = defaultConfig.getDockerHost(); + this.defaultSSLConfig = defaultConfig.getSSLConfig(); + } + + @Test + public void tcHostPropertyIsProvided() { + Mockito + .doReturn("tcp://127.0.0.1:9000") + .when(TestcontainersConfiguration.getInstance()) + .getUserProperty(eq("tc.host"), isNull()); + + TestcontainersHostPropertyClientProviderStrategy strategy = new TestcontainersHostPropertyClientProviderStrategy(); + + TransportConfig transportConfig = strategy.getTransportConfig(); + assertThat(transportConfig.getDockerHost().toString()).isEqualTo("tcp://127.0.0.1:9000"); + assertThat(transportConfig.getSslConfig()).isEqualTo(this.defaultSSLConfig); + } + + @Test + public void tcHostPropertyIsNotProvided() { + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getUserProperty(eq("tc.host"), isNull()); + + TestcontainersHostPropertyClientProviderStrategy strategy = new TestcontainersHostPropertyClientProviderStrategy(); + + TransportConfig transportConfig = strategy.getTransportConfig(); + assertThat(transportConfig.getDockerHost()).isEqualTo(this.defaultDockerHost); + assertThat(transportConfig.getSslConfig()).isEqualTo(this.defaultSSLConfig); + } +}