Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix DockerClientFactory#dockerHostIpAddress #2119

Merged
merged 3 commits into from Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
134 changes: 68 additions & 66 deletions core/src/main/java/org/testcontainers/DockerClientFactory.java
Expand Up @@ -62,8 +62,12 @@ public class DockerClientFactory {
private static DockerClientFactory instance;

// Cached client configuration
private DockerClientProviderStrategy strategy;
private boolean initialized = false;
@VisibleForTesting
DockerClientProviderStrategy strategy;

@VisibleForTesting
DockerClient dockerClient;

private String activeApiVersion;
private String activeExecutionDriver;

Expand All @@ -74,10 +78,8 @@ public class DockerClientFactory {
System.setProperty("org.testcontainers.shaded.io.netty.packagePrefix", "org.testcontainers.shaded.");
}

/**
* Private constructor
*/
private DockerClientFactory() {
@VisibleForTesting
DockerClientFactory() {

}

Expand All @@ -98,70 +100,77 @@ public synchronized static DockerClientFactory instance() {
return instance;
}

@Synchronized
private DockerClientProviderStrategy getOrInitializeStrategy() {
if (strategy != null) {
return strategy;
}

List<DockerClientProviderStrategy> configurationStrategies = new ArrayList<>();
ServiceLoader.load(DockerClientProviderStrategy.class).forEach(configurationStrategies::add);

strategy = DockerClientProviderStrategy.getFirstValidStrategy(configurationStrategies);
return strategy;
}

/**
*
* @return a new initialized Docker client
*/
@Synchronized
public DockerClient client() {

if (strategy != null) {
return strategy.getClient();
if (dockerClient != null) {
return dockerClient;
}

List<DockerClientProviderStrategy> configurationStrategies = new ArrayList<DockerClientProviderStrategy>();
ServiceLoader.load(DockerClientProviderStrategy.class).forEach( cs -> configurationStrategies.add( cs ) );

strategy = DockerClientProviderStrategy.getFirstValidStrategy(configurationStrategies);
final DockerClientProviderStrategy strategy = getOrInitializeStrategy();

String hostIpAddress = strategy.getDockerHostIpAddress();
log.info("Docker host IP address is {}", hostIpAddress);
DockerClient client = strategy.getClient();

if (!initialized) {
Info dockerInfo = client.infoCmd().exec();
Version version = client.versionCmd().exec();
activeApiVersion = version.getApiVersion();
activeExecutionDriver = dockerInfo.getExecutionDriver();
log.info("Connected to docker: \n" +
" Server Version: " + dockerInfo.getServerVersion() + "\n" +
" API Version: " + activeApiVersion + "\n" +
" Operating System: " + dockerInfo.getOperatingSystem() + "\n" +
" Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB");

String ryukContainerId = null;
boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED"));
if (useRyuk) {
ryukContainerId = ResourceReaper.start(hostIpAddress, client);
log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit");
}
final DockerClient client = strategy.getClient();

Info dockerInfo = client.infoCmd().exec();
Version version = client.versionCmd().exec();
activeApiVersion = version.getApiVersion();
activeExecutionDriver = dockerInfo.getExecutionDriver();
log.info("Connected to docker: \n" +
" Server Version: " + dockerInfo.getServerVersion() + "\n" +
" API Version: " + activeApiVersion + "\n" +
" Operating System: " + dockerInfo.getOperatingSystem() + "\n" +
" Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB");

String ryukContainerId = null;
boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED"));
if (useRyuk) {
ryukContainerId = ResourceReaper.start(hostIpAddress, client);
log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit");
}

boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks();
if (checksEnabled) {
VisibleAssertions.info("Checking the system...");
checkDockerVersion(version.getVersion());
if (ryukContainerId != null) {
checkDiskSpace(client, ryukContainerId);
} else {
runInsideDocker(
client,
createContainerCmd -> {
createContainerCmd.withName("testcontainers-checks-" + SESSION_ID);
createContainerCmd.getHostConfig().withAutoRemove(true);
createContainerCmd.withCmd("tail", "-f", "/dev/null");
},
(__, containerId) -> {
checkDiskSpace(client, containerId);
return "";
}
);
}
boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks();
if (checksEnabled) {
VisibleAssertions.info("Checking the system...");
checkDockerVersion(version.getVersion());
if (ryukContainerId != null) {
checkDiskSpace(client, ryukContainerId);
} else {
runInsideDocker(
client,
createContainerCmd -> {
createContainerCmd.withName("testcontainers-checks-" + SESSION_ID);
createContainerCmd.getHostConfig().withAutoRemove(true);
createContainerCmd.withCmd("tail", "-f", "/dev/null");
},
(__, containerId) -> {
checkDiskSpace(client, containerId);
return "";
}
);
}

initialized = true;
}

return client;
dockerClient = client;
return dockerClient;
}

private void checkDockerVersion(String dockerVersion) {
Expand Down Expand Up @@ -237,15 +246,12 @@ public void checkAndPullImage(DockerClient client, String image) {
* @return the IP address of the host running Docker
*/
public String dockerHostIpAddress() {
return strategy.getDockerHostIpAddress();
return getOrInitializeStrategy().getDockerHostIpAddress();
}

public <T> T runInsideDocker(Consumer<CreateContainerCmd> createContainerCmdConsumer, BiFunction<DockerClient, String, T> block) {
if (strategy == null) {
client();
}
// We can't use client() here because it might create an infinite loop
return runInsideDocker(strategy.getClient(), createContainerCmdConsumer, block);
return runInsideDocker(getOrInitializeStrategy().getClient(), createContainerCmdConsumer, block);
}

private <T> T runInsideDocker(DockerClient client, Consumer<CreateContainerCmd> createContainerCmdConsumer, BiFunction<DockerClient, String, T> block) {
Expand Down Expand Up @@ -293,19 +299,15 @@ DiskSpaceUsage parseAvailableDiskSpace(String dfOutput) {
* @return the docker API version of the daemon that we have connected to
*/
public String getActiveApiVersion() {
if (!initialized) {
client();
}
client();
return activeApiVersion;
}

/**
* @return the docker execution driver of the daemon that we have connected to
*/
public String getActiveExecutionDriver() {
if (!initialized) {
client();
}
client();
return activeExecutionDriver;
}

Expand All @@ -314,7 +316,7 @@ public String getActiveExecutionDriver() {
* @return whether or not the currently active strategy is of the provided type
*/
public boolean isUsing(Class<? extends DockerClientProviderStrategy> providerStrategyClass) {
return providerStrategyClass.isAssignableFrom(this.strategy.getClass());
return strategy != null && providerStrategyClass.isAssignableFrom(this.strategy.getClass());
}

private static class NotEnoughDiskSpaceException extends RuntimeException {
Expand Down
Expand Up @@ -7,6 +7,8 @@
import org.testcontainers.dockerclient.LogToStringContainerCallback;
import org.testcontainers.utility.TestcontainersConfiguration;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Test for {@link DockerClientFactory}.
*/
Expand Down Expand Up @@ -43,4 +45,11 @@ public void shouldHandleBigDiskSize() throws Exception {
VisibleAssertions.assertEquals("Available MB is correct", 2982480572L / 1024L, usage.availableMB.orElse(0L));
VisibleAssertions.assertEquals("Available percentage is correct", 31, usage.usedPercent.orElse(0));
}
}

@Test
public void dockerHostIpAddress() {
DockerClientFactory instance = new DockerClientFactory();
instance.strategy = null;
assertThat(instance.dockerHostIpAddress()).isNotNull();
}
}
Expand Up @@ -6,6 +6,7 @@
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

public class DockerClientConfigUtilsTest {
Expand Down Expand Up @@ -33,7 +34,7 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() {
String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration);
assertEquals("12.23.34.45", actual);
}

@Test
public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() {
DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder()
Expand All @@ -43,11 +44,16 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() {
String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration);
assertEquals("12.23.34.45", actual);
}

@Test @Ignore
public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() {
DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("gopher://12.23.34.45").build();
String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration);
assertNull(actual);
}

@Test(timeout = 5_000)
public void getDefaultGateway() {
assertNotNull(DockerClientConfigUtils.getDefaultGateway());
}
}