From 04eaf1f518680b16b16cb33e80d24664f6846330 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Fri, 16 Jan 2015 21:45:40 +0100 Subject: [PATCH 1/4] apply a rebased and squashed unixsocket-branch with a working ssl config. other changes: - make all unit tests succeed on Windows - only create a container when needed - read the complete response when copying a file from a container --- pom.xml | 19 + .../dockerjava/api/command/EventCallback.java | 1 + .../dockerjava/api/model/AuthConfig.java | 2 +- .../dockerjava/core/DockerClientConfig.java | 47 ++- .../dockerjava/core/DockerClientImpl.java | 5 +- .../core/LocalDirectorySSLConfig.java | 14 +- .../com/github/dockerjava/core/SSLConfig.java | 5 +- .../dockerjava/jaxrs/ApacheUnixSocket.java | 327 ++++++++++++++++++ .../jaxrs/ContainerDiffCmdExec.java | 3 +- .../jaxrs/DockerCmdExecFactoryImpl.java | 41 ++- .../dockerjava/jaxrs/EventsCmdExec.java | 2 +- .../jaxrs/RemoveContainerCmdExec.java | 4 +- .../dockerjava/jaxrs/RemoveImageCmdExec.java | 2 +- .../jaxrs/UnixConnectionSocketFactory.java | 85 +++++ .../util/ResponseStatusExceptionFilter.java | 5 +- .../client/AbstractDockerClientTest.java | 6 +- .../core/DockerClientConfigTest.java | 4 +- .../dockerjava/core/DockerClientImplTest.java | 2 +- .../dockerjava/core/GoLangFileMatchTest.java | 3 +- .../CopyFileFromContainerCmdImplTest.java | 22 +- .../core/command/EventsCmdImplTest.java | 17 +- .../core/command/ExecStartCmdImplTest.java | 19 +- .../core/command/InfoCmdImplTest.java | 6 +- .../core/command/PullImageCmdImplTest.java | 4 +- .../core/command/PushImageCmdImplTest.java | 1 - 25 files changed, 581 insertions(+), 65 deletions(-) create mode 100644 src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java create mode 100644 src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java diff --git a/pom.xml b/pom.xml index 0b85dc426..1e6a477e9 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,13 @@ + + + jcenter + http://jcenter.bintray.com + + + UTF-8 UTF-8 @@ -64,6 +71,7 @@ 0.3 18.0 1.51 + 2014-11-16T14-41-27 1.0.1 @@ -93,12 +101,23 @@ + + org.glassfish.jersey.connectors + jersey-apache-connector + ${jersey.version} + org.glassfish.jersey.core jersey-client ${jersey.version} + + de.gesellix + unix-socket-factory + ${unix-socket-factory.version} + + org.apache.commons commons-compress diff --git a/src/main/java/com/github/dockerjava/api/command/EventCallback.java b/src/main/java/com/github/dockerjava/api/command/EventCallback.java index 45ac34dc8..18b8669ea 100644 --- a/src/main/java/com/github/dockerjava/api/command/EventCallback.java +++ b/src/main/java/com/github/dockerjava/api/command/EventCallback.java @@ -9,4 +9,5 @@ public interface EventCallback { public void onEvent(Event event); public void onException(Throwable throwable); public void onCompletion(int numEvents); + public boolean isReceiving(); } diff --git a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java index 87307bb5d..42c49bce0 100644 --- a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java +++ b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java @@ -8,7 +8,7 @@ public class AuthConfig { /** * For backwards compatibility. Make sure you update the properties if you change this. * - * @see /docker.io.properties + * @see "/docker.io.properties" */ public static final String DEFAULT_SERVER_ADDRESS = "https://index.docker.io/v1/"; diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java index c90c62cb1..21e5778fd 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java @@ -33,6 +33,9 @@ public class DockerClientConfig implements Serializable { private static final String DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY = "docker.io.enableLoggingFilter"; private static final String DOCKER_IO_DOCKER_CERT_PATH_PROPERTY = "docker.io.dockerCertPath"; private static final String DOCKER_IO_DOCKER_CFG_PATH_PROPERTY = "docker.io.dockerCfgPath"; + // connection pooling properties + private static final String DOCKER_IO_MAX_PER_ROUTE_PROPERTY = "docker.io.perRouteConnections"; + private static final String DOCKER_IO_MAX_TOTAL_PROPERTY = "docker.io.totalConnections"; /** * A map from the environment name to the interval name. */ @@ -49,13 +52,18 @@ public class DockerClientConfig implements Serializable { .put("DOCKER_CFG_PATH", DOCKER_IO_DOCKER_CFG_PATH_PROPERTY) .build(); private static final String DOCKER_IO_PROPERTIES_PROPERTY = "docker.io.properties"; - private final URI uri; + private URI uri; private final String version, username, password, email, serverAddress, dockerCfgPath; private final Integer readTimeout; private final boolean loggingFilterEnabled; private final SSLConfig sslConfig; + + private final int maxTotalConnections; + private final int maxPerRouteConnections; - DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress, String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled, SSLConfig sslConfig) { + DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress, + String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled, SSLConfig sslConfig, + int maxTotalConns, int maxPerRouteConns) { this.uri = uri; this.version = version; this.username = username; @@ -66,6 +74,8 @@ public class DockerClientConfig implements Serializable { this.readTimeout = readTimeout; this.loggingFilterEnabled = loggingFilterEnabled; this.sslConfig = sslConfig; + this.maxTotalConnections = maxTotalConns; + this.maxPerRouteConnections = maxPerRouteConns; } private static Properties loadIncludedDockerProperties(Properties systemProperties) { @@ -194,6 +204,10 @@ public URI getUri() { return uri; } + public void setUri(URI uri) { + this.uri = uri; + } + public String getVersion() { return version; } @@ -329,7 +343,7 @@ public String toString() { public static class DockerClientConfigBuilder { private URI uri; private String version, username, password, email, serverAddress, dockerCfgPath; - private Integer readTimeout; + private Integer readTimeout, maxTotalConnections, maxPerRouteConnections; private boolean loggingFilterEnabled; private SSLConfig sslConfig; @@ -349,7 +363,10 @@ public DockerClientConfigBuilder withProperties(Properties p) { .withReadTimeout(Integer.valueOf(p.getProperty(DOCKER_IO_READ_TIMEOUT_PROPERTY, "0"))) .withLoggingFilter(Boolean.valueOf(p.getProperty(DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY, "true"))) .withDockerCertPath(p.getProperty(DOCKER_IO_DOCKER_CERT_PATH_PROPERTY)) - .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY)); + .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY)) + .withMaxPerRouteConnections(Integer.valueOf(p.getProperty(DOCKER_IO_MAX_PER_ROUTE_PROPERTY, "2"))) + .withMaxTotalConnections(Integer.valueOf(p.getProperty(DOCKER_IO_MAX_TOTAL_PROPERTY, "20"))) + ; } public final DockerClientConfigBuilder withUri(String uri) { @@ -387,6 +404,16 @@ public final DockerClientConfigBuilder withReadTimeout(Integer readTimeout) { this.readTimeout = readTimeout; return this; } + + public final DockerClientConfigBuilder withMaxTotalConnections(Integer maxTotalConnections) { + this.maxTotalConnections = maxTotalConnections; + return this; + } + + public final DockerClientConfigBuilder withMaxPerRouteConnections(Integer maxPerRouteConnections) { + this.maxPerRouteConnections = maxPerRouteConnections; + return this; + } public final DockerClientConfigBuilder withLoggingFilter(boolean loggingFilterEnabled) { this.loggingFilterEnabled = loggingFilterEnabled; @@ -420,8 +447,18 @@ public DockerClientConfig build() { dockerCfgPath, readTimeout, loggingFilterEnabled, - sslConfig + sslConfig, + maxTotalConnections, + maxPerRouteConnections ); } } + + public int getMaxTotalConnections() { + return maxTotalConnections; + } + + public int getMaxPerRoutConnections() { + return maxPerRouteConnections; + } } diff --git a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java index cee364e00..6b829abda 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java @@ -8,18 +8,15 @@ import java.io.InputStream; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.DockerClientException; import com.github.dockerjava.api.command.*; import com.github.dockerjava.api.model.AuthConfig; -import com.github.dockerjava.core.NameParser.HostnameReposName; -import com.github.dockerjava.core.NameParser.ReposTag; import com.github.dockerjava.core.command.*; import com.google.common.base.Preconditions; /** * @author Konstantin Pelykh (kpelykh@gmail.com) * - * @see https://github.com/docker/docker/blob/master/api/client/commands.go + * @see "https://github.com/docker/docker/blob/master/api/client/commands.go" */ public class DockerClientImpl implements Closeable, DockerClient { diff --git a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java index ef57a0de3..6415d0c18 100644 --- a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java +++ b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java @@ -1,19 +1,16 @@ package com.github.dockerjava.core; +import com.github.dockerjava.api.DockerClientException; import com.google.common.base.Objects; import com.google.common.base.Preconditions; - -import com.github.dockerjava.api.DockerClientException; - import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.glassfish.jersey.SslConfigurator; +import javax.net.ssl.SSLContext; import java.io.Serializable; import java.security.KeyStore; import java.security.Security; -import javax.net.ssl.SSLContext; - /** * SSL Config from local files. */ @@ -41,9 +38,6 @@ public SSLContext getSSLContext() { Security.addProvider(new BouncyCastleProvider()); - KeyStore keyStore = CertificateUtils.createKeyStore(dockerCertPath); - KeyStore trustStore = CertificateUtils.createTrustStore(dockerCertPath); - // properties acrobatics not needed for java > 1.6 String httpProtocols = System.getProperty("https.protocols"); System.setProperty("https.protocols", "TLSv1"); @@ -52,9 +46,9 @@ public SSLContext getSSLContext() { System.setProperty("https.protocols", httpProtocols); } - sslConfig.keyStore(keyStore); + sslConfig.keyStore(CertificateUtils.createKeyStore(dockerCertPath)); sslConfig.keyStorePassword("docker"); - sslConfig.trustStore(trustStore); + sslConfig.trustStore(CertificateUtils.createTrustStore(dockerCertPath)); return sslConfig.createSSLContext(); diff --git a/src/main/java/com/github/dockerjava/core/SSLConfig.java b/src/main/java/com/github/dockerjava/core/SSLConfig.java index 21024c4f6..ab6394890 100644 --- a/src/main/java/com/github/dockerjava/core/SSLConfig.java +++ b/src/main/java/com/github/dockerjava/core/SSLConfig.java @@ -1,9 +1,6 @@ package com.github.dockerjava.core; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; +import java.security.*; import javax.net.ssl.SSLContext; diff --git a/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java b/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java new file mode 100644 index 000000000..a4adb1bb7 --- /dev/null +++ b/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java @@ -0,0 +1,327 @@ +package com.github.dockerjava.jaxrs; +/* + * Copyright (c) 2014 Spotify AB. + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + +import com.google.common.collect.Queues; + +import org.newsclub.net.unix.AFUNIXSocket; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; +import java.util.Queue; + +/** + * Provides a socket that wraps an org.newsclub.net.unix.AFUNIXSocket and delays setting options + * until the socket is connected. This is necessary because the Apache HTTP client attempts to + * set options prior to connecting the socket, which doesn't work for Unix sockets since options + * are being set on the underlying file descriptor. Until the socket is connected, the file + * descriptor doesn't exist. + * + * This class also noop's any calls to setReuseAddress, which is called by the Apache client but + * isn't supported by AFUnixSocket. + */ +public class ApacheUnixSocket extends Socket { + + private final AFUNIXSocket inner; + + private final Queue optionsToSet = Queues.newArrayDeque(); + + public ApacheUnixSocket() throws IOException { + this.inner = AFUNIXSocket.newInstance(); + } + + @Override + public void connect(final SocketAddress endpoint) throws IOException { + inner.connect(endpoint); + setAllSocketOptions(); + } + + @Override + public void connect(final SocketAddress endpoint, final int timeout) throws IOException { + inner.connect(endpoint, timeout); + setAllSocketOptions(); + } + + @Override + public void bind(final SocketAddress bindpoint) throws IOException { + inner.bind(bindpoint); + setAllSocketOptions(); + } + + @Override + public InetAddress getInetAddress() { + return inner.getInetAddress(); + } + + @Override + public InetAddress getLocalAddress() { + return inner.getLocalAddress(); + } + + @Override + public int getPort() { + return inner.getPort(); + } + + @Override + public int getLocalPort() { + return inner.getLocalPort(); + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return inner.getRemoteSocketAddress(); + } + + @Override + public SocketAddress getLocalSocketAddress() { + return inner.getLocalSocketAddress(); + } + + @Override + public SocketChannel getChannel() { + return inner.getChannel(); + } + + @Override + public InputStream getInputStream() throws IOException { + return inner.getInputStream(); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return inner.getOutputStream(); + } + + private void setSocketOption(final SocketOptionSetter s) throws SocketException { + if (inner.isConnected()) { + s.run(); + } else { + if (!optionsToSet.offer(s)) { + throw new SocketException("Failed to queue option"); + } + } + } + + private void setAllSocketOptions() throws SocketException { + for (SocketOptionSetter s : optionsToSet) { + s.run(); + } + } + + @Override + public void setTcpNoDelay(final boolean on) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setTcpNoDelay(on); + } + }); + } + + @Override + public boolean getTcpNoDelay() throws SocketException { + return inner.getTcpNoDelay(); + } + + @Override + public void setSoLinger(final boolean on, final int linger) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setSoLinger(on, linger); + } + }); + } + + @Override + public int getSoLinger() throws SocketException { + return inner.getSoLinger(); + } + + @Override + public void sendUrgentData(final int data) throws IOException { + inner.sendUrgentData(data); + } + + @Override + public void setOOBInline(final boolean on) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setOOBInline(on); + } + }); + } + + @Override + public boolean getOOBInline() throws SocketException { + return inner.getOOBInline(); + } + + @Override + public synchronized void setSoTimeout(final int timeout) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setSoTimeout(timeout); + } + }); + } + + @Override + public synchronized int getSoTimeout() throws SocketException { + return inner.getSoTimeout(); + } + + @Override + public synchronized void setSendBufferSize(final int size) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setSendBufferSize(size); + } + }); + } + + @Override + public synchronized int getSendBufferSize() throws SocketException { + return inner.getSendBufferSize(); + } + + @Override + public synchronized void setReceiveBufferSize(final int size) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setReceiveBufferSize(size); + } + }); + } + + @Override + public synchronized int getReceiveBufferSize() throws SocketException { + return inner.getReceiveBufferSize(); + } + + @Override + public void setKeepAlive(final boolean on) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setKeepAlive(on); + } + }); + } + + @Override + public boolean getKeepAlive() throws SocketException { + return inner.getKeepAlive(); + } + + @Override + public void setTrafficClass(final int tc) throws SocketException { + setSocketOption(new SocketOptionSetter() { + @Override + public void run() throws SocketException { + inner.setTrafficClass(tc); + } + }); + } + + @Override + public int getTrafficClass() throws SocketException { + return inner.getTrafficClass(); + } + + @Override + public void setReuseAddress(final boolean on) throws SocketException { + // not supported: Apache client tries to set it, but we want to just ignore it + } + + @Override + public boolean getReuseAddress() throws SocketException { + return inner.getReuseAddress(); + } + + @Override + public synchronized void close() throws IOException { + inner.close(); + } + + @Override + public void shutdownInput() throws IOException { + inner.shutdownInput(); + } + + @Override + public void shutdownOutput() throws IOException { + inner.shutdownOutput(); + } + + @Override + public String toString() { + return inner.toString(); + } + + @Override + public boolean isConnected() { + return inner.isConnected(); + } + + @Override + public boolean isBound() { + return inner.isBound(); + } + + @Override + public boolean isClosed() { + return inner.isClosed(); + } + + @Override + public boolean isInputShutdown() { + return inner.isInputShutdown(); + } + + @Override + public boolean isOutputShutdown() { + return inner.isOutputShutdown(); + } + + @Override + public void setPerformancePreferences(final int connectionTime, final int latency, + final int bandwidth) { + inner.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + interface SocketOptionSetter { + void run() throws SocketException; + } +} diff --git a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java index 0a657ed90..2b7059b33 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java @@ -26,7 +26,8 @@ protected List execute(ContainerDiffCmd command) { WebTarget webResource = getBaseResource().path("/containers/{id}/changes").resolveTemplate("id", command.getContainerId()); LOGGER.trace("GET: {}", webResource); - return webResource.request().accept(MediaType.APPLICATION_JSON).get(new GenericType>() { + return webResource.request().accept(MediaType.APPLICATION_JSON) + .get(new GenericType>() { }); } diff --git a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java index 525e4a586..c91b0d565 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java +++ b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java @@ -8,7 +8,14 @@ import com.github.dockerjava.jaxrs.util.ResponseStatusExceptionFilter; import com.github.dockerjava.jaxrs.util.SelectiveLoggingFilter; import com.google.common.base.Preconditions; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.glassfish.jersey.CommonProperties; +import org.glassfish.jersey.apache.connector.ApacheClientProperties; +import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; @@ -17,6 +24,7 @@ import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import java.io.IOException; +import java.net.URI; import java.util.logging.Logger; public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory { @@ -30,6 +38,7 @@ public void init(DockerClientConfig dockerClientConfig) { Preconditions.checkNotNull(dockerClientConfig, "config was not specified"); ClientConfig clientConfig = new ClientConfig(); + clientConfig.connectorProvider(new ApacheConnectorProvider()); clientConfig.property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true); clientConfig.register(ResponseStatusExceptionFilter.class); @@ -45,20 +54,31 @@ public void init(DockerClientConfig dockerClientConfig) { clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeout); } - ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig); + URI originalUri = dockerClientConfig.getUri(); + SSLContext sslContext; try { - SSLContext ssl = dockerClientConfig.getSslConfig().getSSLContext(); - - if (ssl != null) - clientBuilder.sslContext(ssl); + sslContext = dockerClientConfig.getSslConfig().getSSLContext(); } catch(Exception ex) { throw new DockerClientException("Error in SSL Configuration", ex); } + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(getSchemeRegistry(originalUri, sslContext)); + connManager.setMaxTotal(dockerClientConfig.getMaxTotalConnections()); + connManager.setDefaultMaxPerRoute(dockerClientConfig.getMaxPerRoutConnections()); + clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connManager); + + ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig); + + if (sslContext != null) { + clientBuilder.sslContext(sslContext); + } client = clientBuilder.build(); + if (originalUri.getScheme().equals("unix")) { + dockerClientConfig.setUri(UnixConnectionSocketFactory.sanitizeUri(originalUri)); + } WebTarget webResource = client.target(dockerClientConfig.getUri()); if (dockerClientConfig.getVersion() == null || dockerClientConfig.getVersion().isEmpty()) { @@ -66,9 +86,18 @@ public void init(DockerClientConfig dockerClientConfig) { } else { baseResource = webResource.path("v" + dockerClientConfig.getVersion()); } - } + private org.apache.http.config.Registry getSchemeRegistry(final URI originalUri, SSLContext sslContext) { + RegistryBuilder registryBuilder = RegistryBuilder.create(); + registryBuilder.register("http", PlainConnectionSocketFactory.getSocketFactory()); + if (sslContext != null) { + registryBuilder.register("https", new SSLConnectionSocketFactory(sslContext)); + } + registryBuilder.register("unix", new UnixConnectionSocketFactory(originalUri)); + return registryBuilder.build(); + } + protected WebTarget getBaseResource() { Preconditions.checkNotNull(baseResource, "Factory not initialized. You probably forgot to call init()!"); return baseResource; diff --git a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java index 545d7db98..ffd757e93 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java @@ -67,7 +67,7 @@ public Void call() throws Exception { response = webTarget.request().get(Response.class); InputStream inputStream = response.readEntity(InputStream.class); JsonParser jp = JSON_FACTORY.createParser(inputStream); - while (jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed()) { + while (jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed() && eventCallback.isReceiving()) { eventCallback.onEvent(OBJECT_MAPPER.readValue(jp, Event.class)); numEvents++; } diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java index 7f45bdda2..7a479ce2f 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java @@ -23,8 +23,8 @@ protected Void execute(RemoveContainerCmd command) { .queryParam("force", command.hasForceEnabled() ? "1" : "0"); LOGGER.trace("DELETE: {}", webResource); - String response = webResource.request().accept(MediaType.APPLICATION_JSON).delete(String.class); - LOGGER.trace("Response: {}", response); + /*String response = */webResource.request().accept(MediaType.APPLICATION_JSON).delete().close(); +// LOGGER.trace("Response: {}", response); return null; } diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java index 54fb327b4..6bfeecd71 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java @@ -23,7 +23,7 @@ protected Void execute(RemoveImageCmd command) { .queryParam("noprune", command.hasNoPruneEnabled() ? "1" : "0"); LOGGER.trace("DELETE: {}", webResource); - webResource.request().delete(Response.class); + webResource.request().delete().close(); return null; } diff --git a/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java b/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java new file mode 100644 index 000000000..4b6cfbba3 --- /dev/null +++ b/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java @@ -0,0 +1,85 @@ +package com.github.dockerjava.jaxrs; +/* + * Copyright (c) 2014 Spotify AB. + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + +import org.apache.http.HttpHost; +import org.apache.http.annotation.Immutable; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.protocol.HttpContext; +import org.newsclub.net.unix.AFUNIXSocketAddress; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URI; + +/** + * Provides a ConnectionSocketFactory for connecting Apache HTTP clients to Unix sockets. + */ +@Immutable +public class UnixConnectionSocketFactory implements ConnectionSocketFactory { + + private File socketFile; + + public UnixConnectionSocketFactory(final URI socketUri) { + super(); + + final String filename = socketUri.toString() + .replaceAll("^unix:///", "unix://localhost/") + .replaceAll("^unix://localhost", ""); + + this.socketFile = new File(filename); + } + + public static URI sanitizeUri(final URI uri) { + if (uri.getScheme().equals("unix")) { + return URI.create("unix://localhost:80"); + } else { + return uri; + } + } + + @Override + public Socket createSocket(final HttpContext context) throws IOException { + return new ApacheUnixSocket(); + } + + @Override + public Socket connectSocket(final int connectTimeout, + final Socket socket, + final HttpHost host, + final InetSocketAddress remoteAddress, + final InetSocketAddress localAddress, + final HttpContext context) throws IOException { + try { + socket.connect(new AFUNIXSocketAddress(socketFile), connectTimeout); + } catch (SocketTimeoutException e) { + throw new ConnectTimeoutException(e, null, remoteAddress.getAddress()); + } + + return socket; + } +} diff --git a/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java b/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java index 61d97f93b..42158e01f 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java +++ b/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java @@ -2,6 +2,7 @@ import java.io.EOFException; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.Charset; import javax.ws.rs.client.ClientRequestContext; @@ -63,7 +64,9 @@ public String getBodyAsMessage(ClientResponseContext responseContext) if (contentLength != -1) { byte[] buffer = new byte[contentLength]; try { - IOUtils.readFully(responseContext.getEntityStream(), buffer); + InputStream entityStream = responseContext.getEntityStream(); + IOUtils.readFully(entityStream, buffer); + entityStream.close(); } catch (EOFException e) { return null; diff --git a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java index 3ed64d9a7..71bfb9304 100644 --- a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java +++ b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java @@ -33,7 +33,6 @@ public abstract class AbstractDockerClientTest extends Assert { public static final Logger LOG = LoggerFactory .getLogger(AbstractDockerClientTest.class); - public static final String DOCKER_JAVA = "dockerjava"; protected DockerClient dockerClient; @@ -120,7 +119,8 @@ protected String asString(InputStream response) { logwriter.write(line + (itr.hasNext() ? "\n" : "")); //LOG.info("line: "+line); } - + response.close(); + return logwriter.toString(); } catch (IOException e) { throw new RuntimeException(e); @@ -150,7 +150,7 @@ public static boolean available(int port) { ds = new DatagramSocket(port); ds.setReuseAddress(true); return true; - } catch (IOException e) { + } catch (IOException ignored) { } finally { if (ds != null) { ds.close(); diff --git a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java index e452e300d..3a61d034d 100644 --- a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java +++ b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java @@ -16,7 +16,7 @@ public class DockerClientConfigTest { public static final DockerClientConfig EXAMPLE_CONFIG = newExampleConfig(); private static DockerClientConfig newExampleConfig() { - return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flam", 877, false, new LocalDirectorySSLConfig("flim")); + return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flam", 877, false, new LocalDirectorySSLConfig("flim"), 20, 2); } @Test @@ -36,6 +36,8 @@ public void environmentDockerHost() throws Exception { // given docker host in env Map env = new HashMap(); env.put("DOCKER_HOST", "tcp://baz:8768"); + // and it looks to be SSL disabled + env.remove("DOCKER_CERT_PATH"); // when you build a config DockerClientConfig config = buildConfig(env, new Properties()); diff --git a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java index a91fa109e..1f5604fe8 100644 --- a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java +++ b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java @@ -10,7 +10,7 @@ public class DockerClientImplTest { @Test public void configuredInstanceAuthConfig() throws Exception { // given a config with null serverAddress - DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null, 0, false, null); + DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null, 0, false, null, 20, 2); DockerClientImpl dockerClient = DockerClientImpl.getInstance(dockerClientConfig); // when we get the auth config diff --git a/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java b/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java index b556a7e5e..215926a56 100644 --- a/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java +++ b/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java @@ -3,7 +3,6 @@ */ package com.github.dockerjava.core; -import java.io.File; import java.io.IOException; import junit.framework.Assert; @@ -19,7 +18,7 @@ public void testMatch(MatchTestCase testCase) throws IOException { String pattern = testCase.pattern; String s = testCase.s; if (GoLangFileMatch.IS_WINDOWS) { - if (pattern.indexOf('\\') > 0) { + if (pattern.indexOf('\\') >= 0) { // no escape allowed on windows. return; } diff --git a/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java index 945b61983..193b787ce 100644 --- a/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java @@ -41,7 +41,7 @@ public void copyFromContainer() throws Exception { // TODO extract this into a shared method CreateContainerResponse container = dockerClient.createContainerCmd("busybox") .withName("docker-java-itest-copyFromContainer") - .withCmd("touch", "/test") + .withCmd("touch", "/copyFromContainer") .exec(); LOG.info("Created container: {}", container); @@ -49,16 +49,22 @@ public void copyFromContainer() throws Exception { dockerClient.startContainerCmd(container.getId()).exec(); - InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/test").exec(); - assertTrue(response.available() > 0, "The file was not copied from the container."); + InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/copyFromContainer").exec(); + boolean bytesAvailable = response.available() > 0; + assertTrue(bytesAvailable, "The file was not copied from the container."); + + // read the stream fully. Otherwise, the underlying stream will not be closed. + String responseAsString = asString(response); + assertNotNull(responseAsString); + assertTrue(responseAsString.length() > 0); } @Test public void copyFromNonExistingContainer() throws Exception { - try { - dockerClient.copyFileFromContainerCmd("non-existing", "/test").exec(); - fail("expected NotFoundException"); - } catch (NotFoundException e) { - } + try { + dockerClient.copyFileFromContainerCmd("non-existing", "/test").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException ignored) { + } } } diff --git a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java index 6935227bc..329f60b7b 100644 --- a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java @@ -19,6 +19,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; @Test(groups = "integration") public class EventsCmdImplTest extends AbstractDockerClientTest { @@ -67,8 +68,7 @@ public void testEventStreamTimeBound() throws InterruptedException, IOException boolean zeroCount = countDownLatch.await(5, TimeUnit.SECONDS); executorService.shutdown(); - - + assertTrue(zeroCount, "Expected 4 events, [create, start, die, stop]"); } @@ -78,7 +78,7 @@ public void testEventStreaming() throws InterruptedException, IOException { TimeUnit.SECONDS.sleep(1); CountDownLatch countDownLatch = new CountDownLatch(KNOWN_NUM_EVENTS); - EventCallback eventCallback = new EventCallbackTest(countDownLatch); + EventCallbackTest eventCallback = new EventCallbackTest(countDownLatch); EventsCmd eventsCmd = dockerClient.eventsCmd(eventCallback).withSince(getEpochTime()); ExecutorService executorService = eventsCmd.exec(); @@ -87,6 +87,7 @@ public void testEventStreaming() throws InterruptedException, IOException { boolean zeroCount = countDownLatch.await(5, TimeUnit.SECONDS); executorService.shutdown(); + eventCallback.close(); assertTrue(zeroCount, "Expected 4 events, [create, start, die, stop]"); } @@ -105,11 +106,16 @@ private int generateEvents() { private class EventCallbackTest implements EventCallback { private final CountDownLatch countDownLatch; + private final AtomicBoolean isReceiving = new AtomicBoolean(true); public EventCallbackTest(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } + public void close() { + isReceiving.set(false); + } + @Override public void onEvent(Event event) { LOG.info("Received event #{}: {}", countDownLatch.getCount(), event); @@ -125,5 +131,10 @@ public void onException(Throwable throwable) { public void onCompletion(int numEvents) { LOG.info("Number of events received: {}", numEvents); } + + @Override + public boolean isReceiving() { + return isReceiving.get(); + } } } diff --git a/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java index a8c3fe8a1..497c44c1e 100644 --- a/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java @@ -42,19 +42,26 @@ public void execStartTest() throws Exception { String containerName = "generated_" + new SecureRandom().nextInt(); CreateContainerResponse container = dockerClient - .createContainerCmd("busybox").withCmd("top") + .createContainerCmd("busybox") + .withCmd("top") .withName(containerName).exec(); - LOG.info("Created container {}", container.toString()); - assertThat(container.getId(), not(isEmptyString())); dockerClient.startContainerCmd(container.getId()).exec(); - ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()).withAttachStdout(true).withCmd("touch","file.log").exec(); + ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()) + .withAttachStdout(true) + .withCmd("touch", "/execStartTest.log").exec(); dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(); - InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/file.log").exec(); - assertTrue(response.available() > 0, "The file was not copied from the container."); + InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/execStartTest.log").exec(); + boolean bytesAvailable = response.available() > 0; + assertTrue(bytesAvailable, "The file was not copied from the container."); + + // read the stream fully. Otherwise, the underlying stream will not be closed. + String responseAsString = asString(response); + assertNotNull(responseAsString); + assertTrue(responseAsString.length() > 0); } } diff --git a/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java index 37214418c..a0a272f2c 100644 --- a/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java @@ -45,6 +45,7 @@ public void afterMethod(ITestResult result) { public void info() throws DockerException { // Make sure that there is at least one container for the assertion // TODO extract this into a shared method + if (dockerClient.listContainersCmd().withShowAll(true).exec().size() == 0) { CreateContainerResponse container = dockerClient.createContainerCmd("busybox") .withName("docker-java-itest-info") .withCmd("touch", "/test") @@ -54,8 +55,9 @@ public void info() throws DockerException { assertThat(container.getId(), not(isEmptyOrNullString())); dockerClient.startContainerCmd(container.getId()).exec(); + } - Info dockerInfo = dockerClient.infoCmd().exec(); + Info dockerInfo = dockerClient.infoCmd().exec(); LOG.info(dockerInfo.toString()); assertTrue(dockerInfo.toString().contains("containers")); @@ -68,6 +70,4 @@ public void info() throws DockerException { assertTrue(dockerInfo.getNGoroutines() > 0); assertTrue(dockerInfo.isMemoryLimit()); } - - } diff --git a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java index 394e86bd4..31a101f1c 100644 --- a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java @@ -109,7 +109,9 @@ public void testPullImage() throws DockerException, IOException { public void testPullNonExistingImage() throws DockerException, IOException { // does not throw an exception - dockerClient.pullImageCmd("nonexisting/foo").exec(); + InputStream is = dockerClient.pullImageCmd("nonexisting/foo").exec(); + // stream needs to be fully read in order to close the underlying connection + this.asString(is); try { dockerClient.pullImageCmd("non-existing/foo").exec(); diff --git a/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java index 2e2c9134d..f409aebf7 100644 --- a/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java @@ -71,6 +71,5 @@ public void pushExistentImage() throws Exception { assertThat(asString(dockerClient.pushImageCmd(username + "/xxx").exec()), containsString("error")); } - } From bce65f09fe9ee9b6904c9687df17bdbc1c42bd5d Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sat, 17 Jan 2015 21:27:34 +0100 Subject: [PATCH 2/4] add Dockerfile with minimal build environment --- .dockerignore | 1 + Dockerfile | 18 ++++++++++++++++++ .../core/command/EventsCmdImplTest.java | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..1de565933 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..eea3db562 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM java:7 +MAINTAINER https://github.com/docker-java/docker-java + +ENV HOME /root +ENV M2_HOME /opt/apache-maven-3.0.5 + +RUN wget http://www.eu.apache.org/dist/maven/maven-3/3.0.5/binaries/apache-maven-3.0.5-bin.tar.gz -O /tmp/apache-maven-3.0.5-bin.tar.gz \ + && cd /tmp \ + && tar xzf apache-maven-3.0.5-bin.tar.gz \ + && mkdir -p /opt \ + && mv apache-maven-3.0.5 /opt \ + && rm apache-maven-3.0.5-bin.tar.gz + +WORKDIR /project +ADD . /project/ + +#ENTRYPOINT $M2_HOME/bin/mvn +CMD $M2_HOME/bin/mvn verify diff --git a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java index 329f60b7b..941657a19 100644 --- a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java @@ -60,7 +60,7 @@ public void testEventStreamTimeBound() throws InterruptedException, IOException String endTime = getEpochTime(); CountDownLatch countDownLatch = new CountDownLatch(expectedEvents); - EventCallback eventCallback = new EventCallbackTest(countDownLatch); + EventCallbackTest eventCallback = new EventCallbackTest(countDownLatch); EventsCmd eventsCmd = dockerClient.eventsCmd(eventCallback).withSince(startTime).withUntil(endTime); ExecutorService executorService = eventsCmd.exec(); @@ -68,6 +68,7 @@ public void testEventStreamTimeBound() throws InterruptedException, IOException boolean zeroCount = countDownLatch.await(5, TimeUnit.SECONDS); executorService.shutdown(); + eventCallback.close(); assertTrue(zeroCount, "Expected 4 events, [create, start, die, stop]"); } From 0319b14b2eabf88de3be5e7333f96c728d83ad50 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 18 Jan 2015 12:30:15 +0100 Subject: [PATCH 3/4] fix client config test to handle different develeoper environments --- .dockerignore | 3 ++- .../core/DockerClientConfigTest.java | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 1de565933..a96e5522b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ -target \ No newline at end of file +.git/ +target/ diff --git a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java index 3a61d034d..4611f4307 100644 --- a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java +++ b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java @@ -84,7 +84,9 @@ public void environmentDockerHostWithInvalidTlsVerify() throws Exception { // given docker host in env Map env = new HashMap(System.getenv()); env.put("DOCKER_HOST", "tcp://bar:8768"); - // and it looks to be SSL enabled + // and it looks to be SSL disabled + env.remove("DOCKER_CERT_PATH"); + // and it has an invalid TLS_VERIFY value env.put("DOCKER_TLS_VERIFY", "any value different from '1'"); // when you build a config @@ -94,6 +96,24 @@ public void environmentDockerHostWithInvalidTlsVerify() throws Exception { assertEquals(config.getUri(), URI.create("http://bar:8768")); } + @Test + public void environmentDockerHostWithInvalidTlsVerifyButWithCertPath() throws Exception { + + // given docker host in env + Map env = new HashMap(System.getenv()); + env.put("DOCKER_HOST", "tcp://bar:8768"); + // and it looks to be SSL enabled + env.put("DOCKER_CERT_PATH", "any value"); + // and it has an invalid TLS_VERIFY value + env.put("DOCKER_TLS_VERIFY", "any value different from '1'"); + + // when you build a config + DockerClientConfig config = buildConfig(env, new Properties()); + + // then the URL is that value with "tcp" changed to "https" + assertEquals(config.getUri(), URI.create("https://bar:8768")); + } + @Test public void environment() throws Exception { From f4ddcb35662c9e3d1c9acc6406dec305c369f9c7 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 18 Jan 2015 12:35:14 +0100 Subject: [PATCH 4/4] explicitly declare the Exception as ignored --- .../github/dockerjava/core/command/PullImageCmdImplTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java index 31a101f1c..43291f07c 100644 --- a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java @@ -116,7 +116,7 @@ public void testPullNonExistingImage() throws DockerException, IOException { try { dockerClient.pullImageCmd("non-existing/foo").exec(); fail("expected InternalServerErrorException"); - } catch (InternalServerErrorException e) { + } catch (InternalServerErrorException ignored) { } }