diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java index 94480c2a02..07b581e426 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java @@ -29,6 +29,7 @@ import org.springframework.boot.buildpack.platform.system.Environment; * HTTP transport used for docker access. * * @author Phillip Webb + * @author Scott Frederick * @since 2.3.0 */ public interface HttpTransport { @@ -94,7 +95,7 @@ public interface HttpTransport { */ static HttpTransport create(Environment environment) { HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment); - return (remote != null) ? remote : LocalHttpClientTransport.create(); + return (remote != null) ? remote : LocalHttpClientTransport.create(environment); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java index 7701bcd0ed..8182cb31ae 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java @@ -40,6 +40,7 @@ import org.apache.http.util.Args; import org.springframework.boot.buildpack.platform.socket.DomainSocket; import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket; +import org.springframework.boot.buildpack.platform.system.Environment; /** * {@link HttpClientTransport} that talks to local Docker. @@ -49,15 +50,17 @@ import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket; */ final class LocalHttpClientTransport extends HttpClientTransport { + private static final String DOCKER_HOST = "DOCKER_HOST"; + private static final HttpHost LOCAL_DOCKER_HOST = HttpHost.create("docker://localhost"); private LocalHttpClientTransport(CloseableHttpClient client) { super(client, LOCAL_DOCKER_HOST); } - static LocalHttpClientTransport create() { + static LocalHttpClientTransport create(Environment environment) { HttpClientBuilder builder = HttpClients.custom(); - builder.setConnectionManager(new LocalConnectionManager()); + builder.setConnectionManager(new LocalConnectionManager(environment.get(DOCKER_HOST))); builder.setSchemePortResolver(new LocalSchemePortResolver()); return new LocalHttpClientTransport(builder.build()); } @@ -67,13 +70,13 @@ final class LocalHttpClientTransport extends HttpClientTransport { */ private static class LocalConnectionManager extends BasicHttpClientConnectionManager { - LocalConnectionManager() { - super(getRegistry(), null, null, new LocalDnsResolver()); + LocalConnectionManager(String host) { + super(getRegistry(host), null, null, new LocalDnsResolver()); } - private static Registry getRegistry() { + private static Registry getRegistry(String host) { RegistryBuilder builder = RegistryBuilder.create(); - builder.register("docker", new LocalConnectionSocketFactory()); + builder.register("docker", new LocalConnectionSocketFactory(host)); return builder.build(); } @@ -103,12 +106,18 @@ final class LocalHttpClientTransport extends HttpClientTransport { private static final String WINDOWS_NAMED_PIPE_PATH = "//./pipe/docker_engine"; + private final String host; + + LocalConnectionSocketFactory(String host) { + this.host = host; + } + @Override public Socket createSocket(HttpContext context) throws IOException { if (Platform.isWindows()) { - return NamedPipeSocket.get(WINDOWS_NAMED_PIPE_PATH); + return NamedPipeSocket.get((this.host != null) ? this.host : WINDOWS_NAMED_PIPE_PATH); } - return DomainSocket.get(DOMAIN_SOCKET_PATH); + return DomainSocket.get((this.host != null) ? this.host : DOMAIN_SOCKET_PATH); } @Override diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java index 6d365a73fa..22daec96e8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java @@ -16,6 +16,9 @@ package org.springframework.boot.buildpack.platform.docker.transport; +import java.nio.file.Files; +import java.nio.file.Paths; + import javax.net.ssl.SSLContext; import org.apache.http.HttpHost; @@ -53,7 +56,10 @@ final class RemoteHttpClientTransport extends HttpClientTransport { static RemoteHttpClientTransport createIfPossible(Environment environment, SslContextFactory sslContextFactory) { String host = environment.get(DOCKER_HOST); - return (host != null) ? create(environment, sslContextFactory, HttpHost.create(host)) : null; + if (host == null || Files.exists(Paths.get(host))) { + return null; + } + return create(environment, sslContextFactory, HttpHost.create(host)); } private static RemoteHttpClientTransport create(Environment environment, SslContextFactory sslContextFactory, diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java index 5821cac946..39cf67b366 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java @@ -16,10 +16,14 @@ package org.springframework.boot.buildpack.platform.docker.transport; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.Map; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; @@ -27,16 +31,25 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link HttpTransport}. * * @author Phillip Webb + * @author Scott Frederick */ class HttpTransportTests { @Test - void createWhenHasDockerHostVariableReturnsRemote() { - Map environment = Collections.singletonMap("DOCKER_HOST", "192.168.1.0"); + void createWhenDockerHostVariableIsAddressReturnsRemote() { + Map environment = Collections.singletonMap("DOCKER_HOST", "tcp://192.168.1.0"); HttpTransport transport = HttpTransport.create(environment::get); assertThat(transport).isInstanceOf(RemoteHttpClientTransport.class); } + @Test + void createWhenDockerHostVariableIsFileReturnsLocal(@TempDir Path tempDir) throws IOException { + String dummySocketFilePath = Files.createTempFile(tempDir, "http-transport", null).toAbsolutePath().toString(); + Map environment = Collections.singletonMap("DOCKER_HOST", dummySocketFilePath); + HttpTransport transport = HttpTransport.create(environment::get); + assertThat(transport).isInstanceOf(LocalHttpClientTransport.class); + } + @Test void createWhenDoesNotHaveDockerHostVariableReturnsLocal() { HttpTransport transport = HttpTransport.create((name) -> null); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java index 8efd3311e5..784fa717c3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java @@ -16,6 +16,9 @@ package org.springframework.boot.buildpack.platform.docker.transport; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Consumer; @@ -24,6 +27,7 @@ import javax.net.ssl.SSLContext; import org.apache.http.HttpHost; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.springframework.boot.buildpack.platform.docker.ssl.SslContextFactory; @@ -40,7 +44,7 @@ import static org.mockito.Mockito.mock; */ class RemoteHttpClientTransportTests { - private Map environment = new LinkedHashMap<>(); + private final Map environment = new LinkedHashMap<>(); @Test void createIfPossibleWhenDockerHostIsNotSetReturnsNull() { @@ -49,7 +53,16 @@ class RemoteHttpClientTransportTests { } @Test - void createIfPossibleWhenDockerHostIsSetReturnsTransport() { + void createIfPossibleWhenDockerHostIsFileReturnsNull(@TempDir Path tempDir) throws IOException { + String dummySocketFilePath = Files.createTempFile(tempDir, "remote-transport", null).toAbsolutePath() + .toString(); + this.environment.put("DOCKER_HOST", dummySocketFilePath); + RemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(this.environment::get); + assertThat(transport).isNull(); + } + + @Test + void createIfPossibleWhenDockerHostIsAddressReturnsTransport() { this.environment.put("DOCKER_HOST", "tcp://192.168.1.2:2376"); RemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(this.environment::get); assertThat(transport).isNotNull();