diff --git a/pom.xml b/pom.xml index 31ef5c969..af33917b8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 @@ -201,6 +202,28 @@ 3.0.0 provided + + + io.netty + netty-codec-http + 4.1.0.Beta7 + + + io.netty + netty-handler + 4.1.0.Beta7 + + + io.netty + netty-handler-proxy + 4.1.0.Beta7 + + + io.netty + netty-transport-native-epoll + 4.1.0.Beta7 + linux-x86_64 + @@ -215,6 +238,13 @@ + + + + + + + diff --git a/src/main/java/com/github/dockerjava/api/command/AsyncDockerCmd.java b/src/main/java/com/github/dockerjava/api/command/AsyncDockerCmd.java index 78ee978fa..221d3d165 100644 --- a/src/main/java/com/github/dockerjava/api/command/AsyncDockerCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/AsyncDockerCmd.java @@ -8,7 +8,7 @@ /** * * - * @author marcus + * @author Marcus Linke * */ public interface AsyncDockerCmd, A_RES_T> extends DockerCmd { diff --git a/src/main/java/com/github/dockerjava/api/command/AttachContainerCmd.java b/src/main/java/com/github/dockerjava/api/command/AttachContainerCmd.java index 13979fb8b..6326fa13b 100644 --- a/src/main/java/com/github/dockerjava/api/command/AttachContainerCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/AttachContainerCmd.java @@ -43,6 +43,9 @@ public interface AttachContainerCmd extends AsyncDockerCmd { diff --git a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java index 99a065629..643d95bae 100644 --- a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java @@ -1,14 +1,14 @@ package com.github.dockerjava.api.command; -import com.github.dockerjava.api.model.AuthConfigurations; -import com.github.dockerjava.api.model.BuildResponseItem; +import java.io.File; +import java.io.InputStream; +import java.net.URI; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import java.io.File; -import java.io.InputStream; -import java.net.URI; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.BuildResponseItem; /** * Build an image from Dockerfile. diff --git a/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java b/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java index 391625cfa..08751f3e2 100644 --- a/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java +++ b/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java @@ -1,5 +1,8 @@ package com.github.dockerjava.api.command; +import org.apache.commons.lang.builder.ReflectionToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -12,4 +15,9 @@ public class ExecCreateCmdResponse { public String getId() { return id; } + + @Override + public String toString() { + return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } } diff --git a/src/main/java/com/github/dockerjava/api/command/ExecStartCmd.java b/src/main/java/com/github/dockerjava/api/command/ExecStartCmd.java index 83aedc27a..e102ef71b 100644 --- a/src/main/java/com/github/dockerjava/api/command/ExecStartCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/ExecStartCmd.java @@ -5,9 +5,11 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Frame; -public interface ExecStartCmd extends SyncDockerCmd { +public interface ExecStartCmd extends AsyncDockerCmd { @CheckForNull public String getExecId(); @@ -18,22 +20,26 @@ public interface ExecStartCmd extends SyncDockerCmd { @CheckForNull public Boolean hasTtyEnabled(); + @CheckForNull + public InputStream getStdin(); + public ExecStartCmd withDetach(Boolean detach); public ExecStartCmd withExecId(@Nonnull String execId); public ExecStartCmd withTty(Boolean tty); + public ExecStartCmd withStdIn(InputStream stdin); + /** - * Its the responsibility of the caller to consume and/or close the {@link InputStream} to prevent connection leaks. * * @throws NotFoundException * No such exec instance */ @Override - public InputStream exec() throws NotFoundException; + public > T exec(T resultCallback); - public static interface Exec extends DockerCmdSyncExec { + public static interface Exec extends DockerCmdAsyncExec { } } diff --git a/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java b/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java index d087be34b..b98e6d70d 100644 --- a/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java +++ b/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java @@ -3,7 +3,7 @@ import java.util.List; import java.util.Map; -import com.github.dockerjava.core.RemoteApiVersion; +import javax.annotation.CheckForNull; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; @@ -20,8 +20,7 @@ import com.github.dockerjava.api.model.VolumeBinds; import com.github.dockerjava.api.model.VolumeRW; import com.github.dockerjava.api.model.VolumesRW; - -import javax.annotation.CheckForNull; +import com.github.dockerjava.core.RemoteApiVersion; /** * @@ -285,7 +284,7 @@ public class ContainerState { /** * Unclear - * + * * @since {@link RemoteApiVersion#UNKNOWN_VERSION} */ @CheckForNull diff --git a/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java b/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java index f06a715cb..f4b5076c5 100644 --- a/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java @@ -6,6 +6,7 @@ import javax.annotation.Nonnull; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.model.Frame; /** @@ -69,6 +70,13 @@ public interface LogContainerCmd extends AsyncDockerCmd public LogContainerCmd withSince(Integer since); + /** + * @throws com.github.dockerjava.api.NotFoundException + * No such container + */ + @Override + public > T exec(T resultCallback); + public static interface Exec extends DockerCmdAsyncExec { } diff --git a/src/main/java/com/github/dockerjava/api/command/PushImageCmd.java b/src/main/java/com/github/dockerjava/api/command/PushImageCmd.java index 9b0799553..24cb7fd71 100644 --- a/src/main/java/com/github/dockerjava/api/command/PushImageCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/PushImageCmd.java @@ -3,8 +3,8 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.PushResponseItem; diff --git a/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java b/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java index 8864167f3..cd6da6814 100644 --- a/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java +++ b/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java @@ -6,7 +6,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java b/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java index 09f480021..6512e48d4 100644 --- a/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java @@ -3,8 +3,8 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.WaitResponse; /** 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 93bf4a7bf..0e994daf3 100644 --- a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java +++ b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java @@ -5,8 +5,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_NULL) public class AuthConfig { diff --git a/src/main/java/com/github/dockerjava/api/model/Container.java b/src/main/java/com/github/dockerjava/api/model/Container.java index f6a7dbfd2..dcdf1699d 100644 --- a/src/main/java/com/github/dockerjava/api/model/Container.java +++ b/src/main/java/com/github/dockerjava/api/model/Container.java @@ -6,8 +6,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * diff --git a/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java b/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java index 7c527dfe2..efc5e0248 100644 --- a/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java +++ b/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java @@ -7,8 +7,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * diff --git a/src/main/java/com/github/dockerjava/api/model/Device.java b/src/main/java/com/github/dockerjava/api/model/Device.java index 71402dd68..21aef589a 100644 --- a/src/main/java/com/github/dockerjava/api/model/Device.java +++ b/src/main/java/com/github/dockerjava/api/model/Device.java @@ -6,8 +6,8 @@ import org.apache.commons.lang.builder.HashCodeBuilder; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_NULL) public class Device { diff --git a/src/main/java/com/github/dockerjava/api/model/DriverStatus.java b/src/main/java/com/github/dockerjava/api/model/DriverStatus.java index 0bef3c28d..3e2b5037a 100644 --- a/src/main/java/com/github/dockerjava/api/model/DriverStatus.java +++ b/src/main/java/com/github/dockerjava/api/model/DriverStatus.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * Created by ben on 12/12/13. diff --git a/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java b/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java index 5f8c01670..62018a4e0 100644 --- a/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java +++ b/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java @@ -1,8 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_NULL) public class ErrorDetail { diff --git a/src/main/java/com/github/dockerjava/api/model/ErrorResponse.java b/src/main/java/com/github/dockerjava/api/model/ErrorResponse.java index 6723cd070..172bd5c79 100644 --- a/src/main/java/com/github/dockerjava/api/model/ErrorResponse.java +++ b/src/main/java/com/github/dockerjava/api/model/ErrorResponse.java @@ -1,8 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_NULL) public class ErrorResponse { diff --git a/src/main/java/com/github/dockerjava/api/model/HostConfig.java b/src/main/java/com/github/dockerjava/api/model/HostConfig.java index 35e51927b..edad5cfcb 100644 --- a/src/main/java/com/github/dockerjava/api/model/HostConfig.java +++ b/src/main/java/com/github/dockerjava/api/model/HostConfig.java @@ -1,5 +1,7 @@ package com.github.dockerjava.api.model; +import javax.annotation.CheckForNull; + import org.apache.commons.lang.builder.ToStringBuilder; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -8,8 +10,6 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import javax.annotation.CheckForNull; - @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(Include.NON_NULL) public class HostConfig { diff --git a/src/main/java/com/github/dockerjava/api/model/Image.java b/src/main/java/com/github/dockerjava/api/model/Image.java index 3c84c9584..496db275e 100644 --- a/src/main/java/com/github/dockerjava/api/model/Image.java +++ b/src/main/java/com/github/dockerjava/api/model/Image.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * diff --git a/src/main/java/com/github/dockerjava/api/model/LxcConf.java b/src/main/java/com/github/dockerjava/api/model/LxcConf.java index 779aa4c78..aeb854285 100644 --- a/src/main/java/com/github/dockerjava/api/model/LxcConf.java +++ b/src/main/java/com/github/dockerjava/api/model/LxcConf.java @@ -1,8 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_NULL) public class LxcConf { diff --git a/src/main/java/com/github/dockerjava/api/model/Node.java b/src/main/java/com/github/dockerjava/api/model/Node.java index 902f805b8..9e8580e0a 100644 --- a/src/main/java/com/github/dockerjava/api/model/Node.java +++ b/src/main/java/com/github/dockerjava/api/model/Node.java @@ -1,8 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * A node as returned by the /events API, for instance, when Swarm is used. diff --git a/src/main/java/com/github/dockerjava/api/model/ResponseItem.java b/src/main/java/com/github/dockerjava/api/model/ResponseItem.java index e60afe5de..1bf71fa34 100644 --- a/src/main/java/com/github/dockerjava/api/model/ResponseItem.java +++ b/src/main/java/com/github/dockerjava/api/model/ResponseItem.java @@ -4,11 +4,10 @@ import javax.annotation.CheckForNull; -import com.fasterxml.jackson.annotation.JsonIgnore; - import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java b/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java index cd437667f..34f8e7e57 100644 --- a/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java +++ b/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java @@ -24,7 +24,7 @@ *
* * - * @author marcus + * @author Marcus Linke * */ public class RestartPolicy { diff --git a/src/main/java/com/github/dockerjava/api/model/Statistics.java b/src/main/java/com/github/dockerjava/api/model/Statistics.java index b4ce2d972..21b9ca923 100644 --- a/src/main/java/com/github/dockerjava/api/model/Statistics.java +++ b/src/main/java/com/github/dockerjava/api/model/Statistics.java @@ -8,8 +8,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; /** * Representation of a Docker statistics. diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java index 6439680b9..fa5c77e6a 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java @@ -1,10 +1,6 @@ package com.github.dockerjava.core; -import com.github.dockerjava.api.exception.DockerClientException; -import com.github.dockerjava.api.model.AuthConfig; -import com.github.dockerjava.api.model.AuthConfigurations; -import com.github.dockerjava.core.NameParser.HostnameReposName; -import com.github.dockerjava.core.NameParser.ReposTag; +import static com.google.common.base.Preconditions.checkNotNull; import java.io.File; import java.io.FileInputStream; @@ -17,7 +13,11 @@ import java.util.Map; import java.util.Properties; -import static com.google.common.base.Preconditions.checkNotNull; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.core.NameParser.HostnameReposName; +import com.github.dockerjava.core.NameParser.ReposTag; public class DockerClientConfig implements Serializable { diff --git a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java index f05a7a744..62df4aacb 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java @@ -14,6 +14,7 @@ import com.github.dockerjava.api.command.CommitCmd; import com.github.dockerjava.api.command.ContainerDiffCmd; import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; +import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.api.command.CopyFileFromContainerCmd; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateImageCmd; @@ -54,7 +55,6 @@ import com.github.dockerjava.core.command.CommitCmdImpl; import com.github.dockerjava.core.command.ContainerDiffCmdImpl; import com.github.dockerjava.core.command.CopyArchiveFromContainerCmdImpl; -import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.core.command.CopyArchiveToContainerCmdImpl; import com.github.dockerjava.core.command.CopyFileFromContainerCmdImpl; import com.github.dockerjava.core.command.CreateContainerCmdImpl; diff --git a/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java b/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java index 8ce237c72..ef798d68d 100644 --- a/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java +++ b/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java @@ -7,9 +7,10 @@ import java.util.ArrayList; import java.util.List; -import com.github.dockerjava.core.exception.GoLangFileMatchException; import org.apache.commons.lang.StringUtils; +import com.github.dockerjava.core.exception.GoLangFileMatchException; + /** * Implementation of golang's file.Match * diff --git a/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java b/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java index 1bdfc1669..febdc48fd 100644 --- a/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java +++ b/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java @@ -6,9 +6,10 @@ import java.io.File; import java.util.List; -import com.github.dockerjava.core.util.FilePathUtil; import org.apache.commons.io.filefilter.AbstractFileFilter; +import com.github.dockerjava.core.util.FilePathUtil; + public class GoLangMatchFileFilter extends AbstractFileFilter { private final File base; diff --git a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java index 7bc7f5c8b..e39a2bc40 100644 --- a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java +++ b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java @@ -7,11 +7,11 @@ import javax.net.ssl.SSLContext; -import com.github.dockerjava.core.util.CertificateUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.glassfish.jersey.SslConfigurator; import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.core.util.CertificateUtils; /** * SSL Config from local files. diff --git a/src/main/java/com/github/dockerjava/core/NameParser.java b/src/main/java/com/github/dockerjava/core/NameParser.java index 10ad10bd8..ba2948fb8 100644 --- a/src/main/java/com/github/dockerjava/core/NameParser.java +++ b/src/main/java/com/github/dockerjava/core/NameParser.java @@ -5,12 +5,12 @@ import java.util.regex.Pattern; -import com.github.dockerjava.core.exception.InvalidRepositoryNameException; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.core.exception.InvalidRepositoryNameException; public class NameParser { diff --git a/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java b/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java index 4f3515156..63269ce55 100644 --- a/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java +++ b/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java @@ -1,14 +1,14 @@ package com.github.dockerjava.core; +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.base.Strings; -import java.io.Serializable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Bean to encapsulate the version of the Docker Remote (REST) API diff --git a/src/main/java/com/github/dockerjava/core/async/FrameStreamProcessor.java b/src/main/java/com/github/dockerjava/core/async/FrameStreamProcessor.java index 220cd80ef..3070930d6 100644 --- a/src/main/java/com/github/dockerjava/core/async/FrameStreamProcessor.java +++ b/src/main/java/com/github/dockerjava/core/async/FrameStreamProcessor.java @@ -13,7 +13,7 @@ /** * * - * @author marcus + * @author Marcus Linke * */ public class FrameStreamProcessor implements ResponseStreamProcessor { diff --git a/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java b/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java index 522d5b189..7e6c497e6 100644 --- a/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java +++ b/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java @@ -14,7 +14,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class JsonStreamProcessor implements ResponseStreamProcessor { diff --git a/src/main/java/com/github/dockerjava/core/async/ResponseStreamProcessor.java b/src/main/java/com/github/dockerjava/core/async/ResponseStreamProcessor.java index 879a8c305..5c93801d3 100644 --- a/src/main/java/com/github/dockerjava/core/async/ResponseStreamProcessor.java +++ b/src/main/java/com/github/dockerjava/core/async/ResponseStreamProcessor.java @@ -9,7 +9,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public interface ResponseStreamProcessor { diff --git a/src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java b/src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java index 44af625af..3a62ae46a 100644 --- a/src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java +++ b/src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java @@ -19,7 +19,7 @@ /** * Abstract template implementation of {@link ResultCallback} * - * @author marcus + * @author Marcus Linke * */ public abstract class ResultCallbackTemplate, A_RES_T> implements diff --git a/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java b/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java index 15e92d474..0c7877503 100644 --- a/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java +++ b/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java @@ -11,10 +11,10 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.command.DockerCmd; import com.github.dockerjava.api.command.DockerCmdSyncExec; import com.github.dockerjava.api.command.SyncDockerCmd; +import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.AuthConfig; public abstract class AbstrDockerCmd, RES_T> implements SyncDockerCmd { diff --git a/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java index 629990ff1..89e27c8ea 100644 --- a/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java @@ -2,6 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; +import java.io.InputStream; + import com.github.dockerjava.api.command.AttachContainerCmd; import com.github.dockerjava.api.model.Frame; @@ -17,6 +19,8 @@ * - true or false, includes stdout log. Defaults to false. * @param stderr * - true or false, includes stderr log. Defaults to false. + * @param stdin + * - null or {@link InputStream}, pass stream to stdin of the container. * @param timestamps * - true or false, if true, print timestamps for every log line. Defaults to false. */ @@ -27,6 +31,8 @@ public class AttachContainerCmdImpl extends AbstrAsyncDockerCmd { diff --git a/src/main/java/com/github/dockerjava/core/command/AuthCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/AuthCmdImpl.java index 16ebe03f8..e0a790c32 100644 --- a/src/main/java/com/github/dockerjava/core/command/AuthCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/AuthCmdImpl.java @@ -1,7 +1,7 @@ package com.github.dockerjava.core.command; -import com.github.dockerjava.api.exception.UnauthorizedException; import com.github.dockerjava.api.command.AuthCmd; +import com.github.dockerjava.api.exception.UnauthorizedException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.AuthResponse; diff --git a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java index 8511a60fe..67bcdf45f 100644 --- a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java @@ -10,8 +10,8 @@ import com.github.dockerjava.api.command.BuildImageCmd; import com.github.dockerjava.api.model.AuthConfigurations; import com.github.dockerjava.api.model.BuildResponseItem; -import com.github.dockerjava.core.util.FilePathUtil; import com.github.dockerjava.core.dockerfile.Dockerfile; +import com.github.dockerjava.core.util.FilePathUtil; /** * diff --git a/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java b/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java index 2536b891b..06c6b1e51 100644 --- a/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java @@ -5,6 +5,8 @@ import java.util.concurrent.TimeUnit; +import javax.annotation.CheckForNull; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,11 +14,9 @@ import com.github.dockerjava.api.model.BuildResponseItem; import com.github.dockerjava.core.async.ResultCallbackTemplate; -import javax.annotation.CheckForNull; - /** * - * @author marcus + * @author Marcus Linke * */ public class BuildImageResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java index b619dee78..534cce52c 100644 --- a/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java @@ -3,8 +3,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.CommitCmd; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.ExposedPorts; import com.github.dockerjava.api.model.Volumes; diff --git a/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java index 3d788ac7b..eb6baa5ab 100644 --- a/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java @@ -4,10 +4,10 @@ import java.util.List; +import com.github.dockerjava.api.command.ContainerDiffCmd; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.api.command.ContainerDiffCmd; import com.github.dockerjava.api.model.ChangeLog; /** diff --git a/src/main/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImpl.java index 93c7e807c..3976834a4 100644 --- a/src/main/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImpl.java @@ -5,8 +5,8 @@ import java.io.InputStream; import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * diff --git a/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java index 555569f16..6b5cea08a 100644 --- a/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java @@ -1,5 +1,7 @@ package com.github.dockerjava.core.command; +import static com.google.common.base.Preconditions.checkNotNull; + import java.util.List; import java.util.Map; @@ -9,10 +11,10 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.dockerjava.api.exception.ConflictException; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.ConflictException; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Capability; import com.github.dockerjava.api.model.Device; @@ -30,8 +32,6 @@ import com.github.dockerjava.api.model.Volumes; import com.github.dockerjava.api.model.VolumesFrom; -import static com.google.common.base.Preconditions.checkNotNull; - /** * * Creates a new container. diff --git a/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java b/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java index 29efac6ca..c731b863e 100644 --- a/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java @@ -11,7 +11,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class EventsResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java index 2c946f1cb..14da4626a 100644 --- a/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java @@ -3,11 +3,11 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.github.dockerjava.api.exception.NotFoundException; +import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.ExecCreateCmd; import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.api.exception.NotFoundException; @JsonInclude(Include.NON_NULL) public class ExecCreateCmdImpl extends AbstrDockerCmd implements ExecCreateCmd { diff --git a/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java index a8e1742a0..f77460730 100644 --- a/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java @@ -4,15 +4,20 @@ import java.io.InputStream; -import com.github.dockerjava.api.exception.NotFoundException; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Frame; -public class ExecStartCmdImpl extends AbstrDockerCmd implements ExecStartCmd { +public class ExecStartCmdImpl extends AbstrAsyncDockerCmd implements ExecStartCmd { private String execId; private Boolean detach, tty; + private InputStream stdin; + public ExecStartCmdImpl(ExecStartCmd.Exec exec, String execId) { super(exec); withExecId(execId); @@ -40,6 +45,13 @@ public Boolean hasTtyEnabled() { return tty; } + @Override + @JsonIgnore + public InputStream getStdin() { + return stdin; + } + + @Override public ExecStartCmd withDetach(Boolean detach) { this.detach = detach; @@ -52,13 +64,18 @@ public ExecStartCmd withTty(Boolean tty) { return this; } + @Override + public ExecStartCmd withStdIn(InputStream stdin) { + this.stdin = stdin; + return this; + } + /** * @throws NotFoundException * No such exec instance */ @Override - public InputStream exec() throws NotFoundException { - return super.exec(); + public > T exec(T resultCallback) { + return super.exec(resultCallback); } - } diff --git a/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java b/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java new file mode 100644 index 000000000..ebf1d08a1 --- /dev/null +++ b/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java @@ -0,0 +1,59 @@ +package com.github.dockerjava.core.command; + +import java.io.IOException; +import java.io.OutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.async.ResultCallbackTemplate; + +/** + * + * @author Marcus Linke + * + */ +public class ExecStartResultCallback extends ResultCallbackTemplate { + + private final static Logger LOGGER = LoggerFactory.getLogger(ExecStartResultCallback.class); + + private OutputStream stdout, stderr; + + public ExecStartResultCallback(OutputStream stdout, OutputStream stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + public ExecStartResultCallback() { + this(null, null); + } + + @Override + public void onNext(Frame frame) { + if (frame != null) { + try { + switch (frame.getStreamType()) { + case STDOUT: + if (stdout != null) { + stdout.write(frame.getPayload()); + stdout.flush(); + } + break; + case STDERR: + if (stderr != null) { + stderr.write(frame.getPayload()); + stderr.flush(); + } + break; + default: + LOGGER.error("unknown stream type:" + frame.getStreamType()); + } + } catch (IOException e) { + onError(e); + } + + } + LOGGER.debug(frame.toString()); + } +} diff --git a/src/main/java/com/github/dockerjava/core/command/FrameReader.java b/src/main/java/com/github/dockerjava/core/command/FrameReader.java index 78db8359f..0e885082a 100644 --- a/src/main/java/com/github/dockerjava/core/command/FrameReader.java +++ b/src/main/java/com/github/dockerjava/core/command/FrameReader.java @@ -16,11 +16,12 @@ public class FrameReader implements AutoCloseable { private static final int HEADER_SIZE = 8; + private final byte[] rawBuffer = new byte[1000]; + private final InputStream inputStream; private Boolean rawStreamDetected = false; - private final byte[] rawBuffer = new byte[1000]; public FrameReader(InputStream inputStream) { this.inputStream = inputStream; @@ -65,6 +66,8 @@ public Frame readFrame() throws IOException { actualHeaderSize += headerCount; } while (actualHeaderSize < HEADER_SIZE); + // HexDump.dump(header, 0, System.err, 0); + StreamType streamType = streamType(header[0]); if (streamType.equals(StreamType.RAW)) { diff --git a/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java index f090d3a76..51b1bdf5a 100644 --- a/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java @@ -2,9 +2,9 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.InspectContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; /** * Inspect the details of a container. diff --git a/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java index d1c0d7140..22d6d70f4 100644 --- a/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java @@ -1,8 +1,8 @@ package com.github.dockerjava.core.command; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.InspectExecCmd; import com.github.dockerjava.api.command.InspectExecResponse; +import com.github.dockerjava.api.exception.NotFoundException; import com.google.common.base.Preconditions; public class InspectExecCmdImpl extends AbstrDockerCmd implements InspectExecCmd { diff --git a/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java index 1f9735db8..48dd30757 100644 --- a/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java @@ -2,9 +2,9 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.InspectImageCmd; import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.exception.NotFoundException; /** * Inspect the details of an image. diff --git a/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java index 3b51bd346..a23d0caa5 100644 --- a/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java @@ -2,8 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.KillContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * Kill a running container. diff --git a/src/main/java/com/github/dockerjava/core/command/LogContainerResultCallback.java b/src/main/java/com/github/dockerjava/core/command/LogContainerResultCallback.java index ffe46baf8..b7fc81cb2 100644 --- a/src/main/java/com/github/dockerjava/core/command/LogContainerResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/LogContainerResultCallback.java @@ -11,7 +11,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class LogContainerResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java index 0e35f0472..a8caf3091 100644 --- a/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java @@ -2,8 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.PauseContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * Pause a container. diff --git a/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java b/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java index 1beb9e3b3..27be12215 100644 --- a/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java @@ -3,6 +3,8 @@ */ package com.github.dockerjava.core.command; +import javax.annotation.CheckForNull; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,11 +12,9 @@ import com.github.dockerjava.api.model.PullResponseItem; import com.github.dockerjava.core.async.ResultCallbackTemplate; -import javax.annotation.CheckForNull; - /** * - * @author marcus + * @author Marcus Linke * */ public class PullImageResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java b/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java index 9bc3b15d7..65ec93c88 100644 --- a/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java @@ -3,6 +3,8 @@ */ package com.github.dockerjava.core.command; +import javax.annotation.CheckForNull; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,11 +12,9 @@ import com.github.dockerjava.api.model.PushResponseItem; import com.github.dockerjava.core.async.ResultCallbackTemplate; -import javax.annotation.CheckForNull; - /** * - * @author marcus + * @author Marcus Linke * */ public class PushImageResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java index 980088c74..0fc2ab626 100644 --- a/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java @@ -2,8 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * Remove a container. diff --git a/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java index d8b8f1181..038a27f2d 100644 --- a/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java @@ -2,8 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.RemoveImageCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * diff --git a/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java index a521fe468..e3621af4f 100644 --- a/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java @@ -3,8 +3,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.RestartContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * Restart a running container. diff --git a/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java index 64480758c..333e32df7 100644 --- a/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java @@ -4,8 +4,8 @@ import java.io.InputStream; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.SaveImageCmd; +import com.github.dockerjava.api.exception.NotFoundException; public class SaveImageCmdImpl extends AbstrDockerCmd implements SaveImageCmd { private String name; diff --git a/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java index 740032815..6f127da23 100644 --- a/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java @@ -5,9 +5,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; +import com.github.dockerjava.api.command.StartContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.exception.NotModifiedException; -import com.github.dockerjava.api.command.StartContainerCmd; /** * Start a container diff --git a/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java index 5c0634c71..7b1e165f5 100644 --- a/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java @@ -3,9 +3,9 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.github.dockerjava.api.command.StopContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.exception.NotModifiedException; -import com.github.dockerjava.api.command.StopContainerCmd; /** * Stop a running container. diff --git a/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java index 77adf1916..19faed3f2 100644 --- a/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java @@ -2,9 +2,9 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.TopContainerCmd; import com.github.dockerjava.api.command.TopContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; /** * List processes running inside a container diff --git a/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java index 2b9b19de3..26e9992b0 100644 --- a/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java @@ -2,8 +2,8 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.command.UnpauseContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; /** * Unpause a container. diff --git a/src/main/java/com/github/dockerjava/core/command/WaitContainerResultCallback.java b/src/main/java/com/github/dockerjava/core/command/WaitContainerResultCallback.java index 5af956cf2..5416d124c 100644 --- a/src/main/java/com/github/dockerjava/core/command/WaitContainerResultCallback.java +++ b/src/main/java/com/github/dockerjava/core/command/WaitContainerResultCallback.java @@ -16,7 +16,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class WaitContainerResultCallback extends ResultCallbackTemplate { diff --git a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java index 46b5642f4..d7173d4d8 100644 --- a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java +++ b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java @@ -1,21 +1,7 @@ package com.github.dockerjava.core.dockerfile; -import com.github.dockerjava.api.exception.DockerClientException; -import com.github.dockerjava.core.util.CompressArchiveUtil; -import com.github.dockerjava.core.util.FilePathUtil; -import com.github.dockerjava.core.GoLangFileMatch; -import com.github.dockerjava.core.exception.GoLangFileMatchException; -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.base.Optional; -import com.google.common.collect.Collections2; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.filefilter.TrueFileFilter; - import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -23,6 +9,21 @@ import java.util.List; import java.util.UUID; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.filefilter.TrueFileFilter; + +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.core.GoLangFileMatch; +import com.github.dockerjava.core.exception.GoLangFileMatchException; +import com.github.dockerjava.core.util.CompressArchiveUtil; +import com.github.dockerjava.core.util.FilePathUtil; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.Collections2; + /** * Parse a Dockerfile. */ @@ -128,10 +129,18 @@ public InputStream buildDockerFolderTar(File directory) { dockerFolderTar = CompressArchiveUtil.archiveTARFiles(directory, filesToAdd, archiveNameWithOutExtension); - final InputStream tarInputStream = FileUtils.openInputStream(dockerFolderTar); + long length = dockerFolderTar.length(); + + final FileInputStream tarInputStream = FileUtils.openInputStream(dockerFolderTar); final File tarFile = dockerFolderTar; return new InputStream() { + + @Override + public int available() throws IOException { + return tarInputStream.available(); + } + @Override public int read() throws IOException { return tarInputStream.read(); diff --git a/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java b/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java index 91ff755db..4f0341c7a 100644 --- a/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java +++ b/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java @@ -8,13 +8,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; + import com.github.dockerjava.api.exception.DockerClientException; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import org.apache.commons.lang.StringUtils; /** * A statement present in a dockerfile. diff --git a/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java b/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java index 384b4b429..19f142593 100644 --- a/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java +++ b/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java @@ -1,11 +1,5 @@ package com.github.dockerjava.core.util; -import org.apache.commons.io.IOUtils; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -25,6 +19,12 @@ import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; + public class CertificateUtils { private CertificateUtils() { // utility class diff --git a/src/main/java/com/github/dockerjava/jaxrs/AbstrAsyncDockerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/AbstrAsyncDockerCmdExec.java index c2f1a3def..eac18ae8d 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/AbstrAsyncDockerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/AbstrAsyncDockerCmdExec.java @@ -1,15 +1,16 @@ package com.github.dockerjava.jaxrs; +import java.io.Closeable; +import java.io.IOException; + +import javax.ws.rs.client.WebTarget; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.AsyncDockerCmd; import com.github.dockerjava.api.command.DockerCmdAsyncExec; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; -import javax.ws.rs.client.WebTarget; -import java.io.Closeable; -import java.io.IOException; - public abstract class AbstrAsyncDockerCmdExec, A_RES_T> extends AbstrDockerCmdExec implements DockerCmdAsyncExec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/AbstrDockerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/AbstrDockerCmdExec.java index b2c61c13e..d8c84663c 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/AbstrDockerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/AbstrDockerCmdExec.java @@ -1,16 +1,18 @@ package com.github.dockerjava.jaxrs; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.IOException; + +import javax.ws.rs.client.WebTarget; + +import org.apache.commons.codec.binary.Base64; + import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.AuthConfigurations; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.RemoteApiVersion; -import org.apache.commons.codec.binary.Base64; - -import javax.ws.rs.client.WebTarget; -import java.io.IOException; - -import static com.google.common.base.Preconditions.checkNotNull; public abstract class AbstrDockerCmdExec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/AbstrSyncDockerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/AbstrSyncDockerCmdExec.java index 4e44d42cd..ed7d3adf0 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/AbstrSyncDockerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/AbstrSyncDockerCmdExec.java @@ -1,13 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.exception.DockerException; +import javax.ws.rs.ProcessingException; +import javax.ws.rs.client.WebTarget; + import com.github.dockerjava.api.command.DockerCmd; import com.github.dockerjava.api.command.DockerCmdSyncExec; +import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.core.DockerClientConfig; -import javax.ws.rs.ProcessingException; -import javax.ws.rs.client.WebTarget; - public abstract class AbstrSyncDockerCmdExec, RES_T> extends AbstrDockerCmdExec implements DockerCmdSyncExec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/AttachContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/AttachContainerCmdExec.java index b272adc78..b3670a8b9 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/AttachContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/AttachContainerCmdExec.java @@ -1,5 +1,10 @@ package com.github.dockerjava.jaxrs; +import javax.ws.rs.client.WebTarget; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.AttachContainerCmd; import com.github.dockerjava.api.model.Frame; @@ -7,10 +12,6 @@ import com.github.dockerjava.core.async.FrameStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.WebTarget; public class AttachContainerCmdExec extends AbstrAsyncDockerCmdExec implements AttachContainerCmd.Exec { @@ -25,12 +26,15 @@ public AttachContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerC protected AbstractCallbackNotifier callbackNotifier(AttachContainerCmd command, ResultCallback resultCallback) { + if (command.getStdin() != null) + throw new UnsupportedOperationException( + "Passing stdin to the container is currently not supported. Try experimental netty engine!"); + WebTarget webTarget = getBaseResource().path("/containers/{id}/attach").resolveTemplate("id", command.getContainerId()); webTarget = booleanQueryParam(webTarget, "logs", command.hasLogsEnabled()); webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled()); - // webTarget = booleanQueryParam(webTarget, "stdin", command.hasStdinEnabled()); webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled()); webTarget = booleanQueryParam(webTarget, "stream", command.hasFollowStreamEnabled()); diff --git a/src/main/java/com/github/dockerjava/jaxrs/AuthCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/AuthCmdExec.java index 247a6a387..6812e397a 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/AuthCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/AuthCmdExec.java @@ -1,17 +1,18 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.exception.UnauthorizedException; -import com.github.dockerjava.api.command.AuthCmd; -import com.github.dockerjava.api.model.AuthResponse; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.AuthCmd; +import com.github.dockerjava.api.exception.UnauthorizedException; +import com.github.dockerjava.api.model.AuthResponse; +import com.github.dockerjava.core.DockerClientConfig; public class AuthCmdExec extends AbstrSyncDockerCmdExec implements AuthCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java index 5ca6eea0b..fd868a7b3 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java @@ -1,5 +1,16 @@ package com.github.dockerjava.jaxrs; +import static javax.ws.rs.client.Entity.entity; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.RequestEntityProcessing; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.BuildImageCmd; import com.github.dockerjava.api.model.AuthConfigurations; @@ -8,16 +19,6 @@ import com.github.dockerjava.core.async.JsonStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier; -import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.client.RequestEntityProcessing; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; - -import static javax.ws.rs.client.Entity.entity; public class BuildImageCmdExec extends AbstrAsyncDockerCmdExec implements BuildImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/CommitCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/CommitCmdExec.java index 8a8fad231..9acb4eff5 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/CommitCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/CommitCmdExec.java @@ -1,15 +1,16 @@ package com.github.dockerjava.jaxrs; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.dockerjava.api.command.CommitCmd; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.dockerjava.api.command.CommitCmd; +import com.github.dockerjava.core.DockerClientConfig; public class CommitCmdExec extends AbstrSyncDockerCmdExec implements CommitCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java index 12ceb2cd0..29cbeebf7 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java @@ -1,15 +1,17 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.ContainerDiffCmd; -import com.github.dockerjava.api.model.ChangeLog; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.List; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; -import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.ContainerDiffCmd; +import com.github.dockerjava.api.model.ChangeLog; +import com.github.dockerjava.core.DockerClientConfig; public class ContainerDiffCmdExec extends AbstrSyncDockerCmdExec> implements ContainerDiffCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/CopyFileFromContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/CopyFileFromContainerCmdExec.java index 10a719cbc..f63b0cb58 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/CopyFileFromContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/CopyFileFromContainerCmdExec.java @@ -1,17 +1,19 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.CopyFileFromContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; + +import java.io.InputStream; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.io.InputStream; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream; public class CopyFileFromContainerCmdExec extends AbstrSyncDockerCmdExec implements CopyFileFromContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/CreateContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/CreateContainerCmdExec.java index bb923289d..651362b1c 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/CreateContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/CreateContainerCmdExec.java @@ -1,15 +1,16 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.CreateContainerCmd; -import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; public class CreateContainerCmdExec extends AbstrSyncDockerCmdExec implements CreateContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/CreateImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/CreateImageCmdExec.java index 3656d9463..d5c40f83b 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/CreateImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/CreateImageCmdExec.java @@ -1,15 +1,16 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.CreateImageCmd; -import com.github.dockerjava.api.command.CreateImageResponse; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CreateImageCmd; +import com.github.dockerjava.api.command.CreateImageResponse; +import com.github.dockerjava.core.DockerClientConfig; public class CreateImageCmdExec extends AbstrSyncDockerCmdExec implements CreateImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java index bac866596..6107c6f7f 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java +++ b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java @@ -3,7 +3,11 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; import java.net.URI; +import java.util.List; import javax.net.ssl.SSLContext; import javax.ws.rs.client.Client; @@ -71,12 +75,6 @@ import com.github.dockerjava.jaxrs.filter.ResponseStatusExceptionFilter; import com.github.dockerjava.jaxrs.filter.SelectiveLoggingFilter; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.ProxySelector; - -import java.util.List; - //import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; // see https://github.com/docker-java/docker-java/issues/196 diff --git a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java index 2b73f2658..395fde4e0 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java @@ -1,5 +1,12 @@ package com.github.dockerjava.jaxrs; +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import javax.ws.rs.client.WebTarget; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.EventsCmd; import com.github.dockerjava.api.model.Event; @@ -7,12 +14,6 @@ import com.github.dockerjava.core.async.JsonStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.GETCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.WebTarget; - -import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; public class EventsCmdExec extends AbstrAsyncDockerCmdExec implements EventsCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/ExecCreateCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ExecCreateCmdExec.java index 79fa04bed..4de6eedd2 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ExecCreateCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ExecCreateCmdExec.java @@ -1,15 +1,16 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.ExecCreateCmd; -import com.github.dockerjava.api.command.ExecCreateCmdResponse; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.ExecCreateCmd; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.DockerClientConfig; public class ExecCreateCmdExec extends AbstrSyncDockerCmdExec implements ExecCreateCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/ExecStartCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ExecStartCmdExec.java index cf850d10c..f737f6e28 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ExecStartCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ExecStartCmdExec.java @@ -1,19 +1,20 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.ExecStartCmd; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.InputStream; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class ExecStartCmdExec extends AbstrSyncDockerCmdExec implements ExecStartCmd.Exec { +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.async.FrameStreamProcessor; +import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; +import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier; + +public class ExecStartCmdExec extends AbstrAsyncDockerCmdExec implements ExecStartCmd.Exec { private static final Logger LOGGER = LoggerFactory.getLogger(ExecStartCmdExec.class); @@ -22,14 +23,13 @@ public ExecStartCmdExec(WebTarget baseResource, DockerClientConfig dockerClientC } @Override - protected InputStream execute(ExecStartCmd command) { - WebTarget webResource = getBaseResource().path("/exec/{id}/start").resolveTemplate("id", command.getExecId()); - - LOGGER.trace("POST: {}", webResource); + protected AbstractCallbackNotifier callbackNotifier(ExecStartCmd command, + ResultCallback resultCallback) { + WebTarget webTarget = getBaseResource().path("/exec/{id}/start").resolveTemplate("id", command.getExecId()); - Response response = webResource.request().accept(MediaType.APPLICATION_JSON) - .post(entity(command, MediaType.APPLICATION_JSON), Response.class); + LOGGER.trace("POST: {}", webTarget); - return new WrappedResponseInputStream(response); + return new POSTCallbackNotifier(new FrameStreamProcessor(), resultCallback, webTarget.request().accept( + MediaType.APPLICATION_JSON), null); } } diff --git a/src/main/java/com/github/dockerjava/jaxrs/InfoCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/InfoCmdExec.java index d1dda0148..c544571ef 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/InfoCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/InfoCmdExec.java @@ -1,13 +1,14 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.InfoCmd; -import com.github.dockerjava.api.model.Info; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.InfoCmd; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.core.DockerClientConfig; public class InfoCmdExec extends AbstrSyncDockerCmdExec implements InfoCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/InspectContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/InspectContainerCmdExec.java index 68790cb69..74bcc801c 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/InspectContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/InspectContainerCmdExec.java @@ -1,13 +1,14 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.InspectContainerCmd; -import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.InspectContainerCmd; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; public class InspectContainerCmdExec extends AbstrSyncDockerCmdExec implements InspectContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/InspectExecCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/InspectExecCmdExec.java index c5127a962..4290d0371 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/InspectExecCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/InspectExecCmdExec.java @@ -1,13 +1,14 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.InspectExecCmd; -import com.github.dockerjava.api.command.InspectExecResponse; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.InspectExecCmd; +import com.github.dockerjava.api.command.InspectExecResponse; +import com.github.dockerjava.core.DockerClientConfig; public class InspectExecCmdExec extends AbstrSyncDockerCmdExec implements InspectExecCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/InspectImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/InspectImageCmdExec.java index 71944e12f..c1ef42424 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/InspectImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/InspectImageCmdExec.java @@ -1,13 +1,14 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.InspectImageCmd; -import com.github.dockerjava.api.command.InspectImageResponse; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.core.DockerClientConfig; public class InspectImageCmdExec extends AbstrSyncDockerCmdExec implements InspectImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/KillContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/KillContainerCmdExec.java index 0c62aee1c..95c8ef83c 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/KillContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/KillContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.KillContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.KillContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class KillContainerCmdExec extends AbstrSyncDockerCmdExec implements KillContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/ListContainersCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ListContainersCmdExec.java index 4b087bc66..4031bfa0d 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ListContainersCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ListContainersCmdExec.java @@ -1,17 +1,19 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.ListContainersCmd; -import com.github.dockerjava.api.model.Container; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import java.util.List; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; -import java.util.List; -import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.ListContainersCmd; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.DockerClientConfig; public class ListContainersCmdExec extends AbstrSyncDockerCmdExec> implements ListContainersCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/ListImagesCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ListImagesCmdExec.java index c6422aa52..9734dfb42 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/ListImagesCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/ListImagesCmdExec.java @@ -1,17 +1,19 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.ListImagesCmd; -import com.github.dockerjava.api.model.Image; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import java.util.List; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; -import java.util.List; -import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.ListImagesCmd; +import com.github.dockerjava.api.model.Image; +import com.github.dockerjava.core.DockerClientConfig; public class ListImagesCmdExec extends AbstrSyncDockerCmdExec> implements ListImagesCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/LogContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/LogContainerCmdExec.java index 349d2e240..87bc83b98 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/LogContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/LogContainerCmdExec.java @@ -1,5 +1,10 @@ package com.github.dockerjava.jaxrs; +import javax.ws.rs.client.WebTarget; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.LogContainerCmd; import com.github.dockerjava.api.model.Frame; @@ -7,10 +12,6 @@ import com.github.dockerjava.core.async.FrameStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.GETCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.WebTarget; public class LogContainerCmdExec extends AbstrAsyncDockerCmdExec implements LogContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/PauseContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/PauseContainerCmdExec.java index 8ba4e6b5d..5e6beb835 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/PauseContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/PauseContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.PauseContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.PauseContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class PauseContainerCmdExec extends AbstrSyncDockerCmdExec implements PauseContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/PingCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/PingCmdExec.java index 974ec427c..ef6215358 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/PingCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/PingCmdExec.java @@ -1,11 +1,12 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.PingCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; +import com.github.dockerjava.api.command.PingCmd; +import com.github.dockerjava.core.DockerClientConfig; public class PingCmdExec extends AbstrSyncDockerCmdExec implements PingCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/PullImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/PullImageCmdExec.java index b68edeb0c..1f0b21bf7 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/PullImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/PullImageCmdExec.java @@ -1,5 +1,15 @@ package com.github.dockerjava.jaxrs; +import static javax.ws.rs.client.Entity.entity; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.model.AuthConfig; @@ -8,15 +18,6 @@ import com.github.dockerjava.core.async.JsonStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.Invocation.Builder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; - -import static javax.ws.rs.client.Entity.entity; public class PullImageCmdExec extends AbstrAsyncDockerCmdExec implements PullImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/PushImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/PushImageCmdExec.java index 3278289a5..2943ef7e8 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/PushImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/PushImageCmdExec.java @@ -1,5 +1,14 @@ package com.github.dockerjava.jaxrs; +import static javax.ws.rs.client.Entity.entity; + +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PushImageCmd; import com.github.dockerjava.api.model.AuthConfig; @@ -8,14 +17,6 @@ import com.github.dockerjava.core.async.JsonStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.Invocation.Builder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; - -import static javax.ws.rs.client.Entity.entity; public class PushImageCmdExec extends AbstrAsyncDockerCmdExec implements PushImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java index f513714f6..d649b57a5 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.RemoveContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class RemoveContainerCmdExec extends AbstrSyncDockerCmdExec implements RemoveContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java index a3ceba4ea..9b362df72 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java @@ -1,11 +1,12 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.RemoveImageCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; +import com.github.dockerjava.api.command.RemoveImageCmd; +import com.github.dockerjava.core.DockerClientConfig; public class RemoveImageCmdExec extends AbstrSyncDockerCmdExec implements RemoveImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/RestartContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RestartContainerCmdExec.java index 496fa450c..765537f44 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/RestartContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/RestartContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.RestartContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.RestartContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class RestartContainerCmdExec extends AbstrSyncDockerCmdExec implements RestartContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/SaveImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/SaveImageCmdExec.java index 77604cf74..f3f9a0d35 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/SaveImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/SaveImageCmdExec.java @@ -1,15 +1,17 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.SaveImageCmd; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.InputStream; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.SaveImageCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream; public class SaveImageCmdExec extends AbstrSyncDockerCmdExec implements SaveImageCmd.Exec { private static final Logger LOGGER = LoggerFactory.getLogger(SaveImageCmdExec.class); diff --git a/src/main/java/com/github/dockerjava/jaxrs/SearchImagesCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/SearchImagesCmdExec.java index ded7fc8c3..90fdd80cd 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/SearchImagesCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/SearchImagesCmdExec.java @@ -1,15 +1,17 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.SearchImagesCmd; -import com.github.dockerjava.api.model.SearchItem; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.List; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; -import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.SearchImagesCmd; +import com.github.dockerjava.api.model.SearchItem; +import com.github.dockerjava.core.DockerClientConfig; public class SearchImagesCmdExec extends AbstrSyncDockerCmdExec> implements SearchImagesCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/StartContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/StartContainerCmdExec.java index 4d0c60111..0f75c4f2f 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/StartContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/StartContainerCmdExec.java @@ -1,14 +1,15 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.StartContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static javax.ws.rs.client.Entity.entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import static javax.ws.rs.client.Entity.entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class StartContainerCmdExec extends AbstrSyncDockerCmdExec implements StartContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/StatsCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/StatsCmdExec.java index f934b895d..8a604603a 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/StatsCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/StatsCmdExec.java @@ -1,5 +1,10 @@ package com.github.dockerjava.jaxrs; +import javax.ws.rs.client.WebTarget; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.StatsCmd; import com.github.dockerjava.api.model.Statistics; @@ -7,10 +12,6 @@ import com.github.dockerjava.core.async.JsonStreamProcessor; import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier; import com.github.dockerjava.jaxrs.async.GETCallbackNotifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.client.WebTarget; public class StatsCmdExec extends AbstrAsyncDockerCmdExec implements StatsCmd.Exec { private static final Logger LOGGER = LoggerFactory.getLogger(StatsCmdExec.class); diff --git a/src/main/java/com/github/dockerjava/jaxrs/StopContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/StopContainerCmdExec.java index eda4e3e30..930ccbb7d 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/StopContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/StopContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.StopContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.StopContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class StopContainerCmdExec extends AbstrSyncDockerCmdExec implements StopContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/TagImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/TagImageCmdExec.java index a74541973..aac15f9dd 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/TagImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/TagImageCmdExec.java @@ -1,11 +1,12 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.TagImageCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; +import com.github.dockerjava.api.command.TagImageCmd; +import com.github.dockerjava.core.DockerClientConfig; public class TagImageCmdExec extends AbstrSyncDockerCmdExec implements TagImageCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/TopContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/TopContainerCmdExec.java index 46a139e39..48b6641a1 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/TopContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/TopContainerCmdExec.java @@ -1,14 +1,15 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.TopContainerCmd; -import com.github.dockerjava.api.command.TopContainerResponse; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.TopContainerCmd; +import com.github.dockerjava.api.command.TopContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; public class TopContainerCmdExec extends AbstrSyncDockerCmdExec implements TopContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/UnpauseContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/UnpauseContainerCmdExec.java index 375ff875f..5c3828358 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/UnpauseContainerCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/UnpauseContainerCmdExec.java @@ -1,12 +1,13 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.UnpauseContainerCmd; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.UnpauseContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; public class UnpauseContainerCmdExec extends AbstrSyncDockerCmdExec implements UnpauseContainerCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/VersionCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/VersionCmdExec.java index 3965e04d6..7fbc92784 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/VersionCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/VersionCmdExec.java @@ -1,13 +1,14 @@ package com.github.dockerjava.jaxrs; -import com.github.dockerjava.api.command.VersionCmd; -import com.github.dockerjava.api.model.Version; -import com.github.dockerjava.core.DockerClientConfig; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import com.github.dockerjava.api.command.VersionCmd; +import com.github.dockerjava.api.model.Version; +import com.github.dockerjava.core.DockerClientConfig; public class VersionCmdExec extends AbstrSyncDockerCmdExec implements VersionCmd.Exec { diff --git a/src/main/java/com/github/dockerjava/jaxrs/async/GETCallbackNotifier.java b/src/main/java/com/github/dockerjava/jaxrs/async/GETCallbackNotifier.java index 996696479..e6f4fd1d2 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/async/GETCallbackNotifier.java +++ b/src/main/java/com/github/dockerjava/jaxrs/async/GETCallbackNotifier.java @@ -11,7 +11,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class GETCallbackNotifier extends AbstractCallbackNotifier { diff --git a/src/main/java/com/github/dockerjava/jaxrs/async/POSTCallbackNotifier.java b/src/main/java/com/github/dockerjava/jaxrs/async/POSTCallbackNotifier.java index 9fe848950..bd96e8250 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/async/POSTCallbackNotifier.java +++ b/src/main/java/com/github/dockerjava/jaxrs/async/POSTCallbackNotifier.java @@ -12,7 +12,7 @@ /** * - * @author marcus + * @author Marcus Linke * */ public class POSTCallbackNotifier extends AbstractCallbackNotifier { diff --git a/src/main/java/com/github/dockerjava/jaxrs/connector/ApacheConnectorClientResponse.java b/src/main/java/com/github/dockerjava/jaxrs/connector/ApacheConnectorClientResponse.java index a4d68e202..d358f574a 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/connector/ApacheConnectorClientResponse.java +++ b/src/main/java/com/github/dockerjava/jaxrs/connector/ApacheConnectorClientResponse.java @@ -14,7 +14,7 @@ * * https://java.net/jira/browse/JERSEY-2852 * - * @author marcus + * @author Marcus Linke * */ public class ApacheConnectorClientResponse extends ClientResponse { diff --git a/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java b/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java index e597b594b..e119c7303 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java +++ b/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java @@ -24,7 +24,7 @@ /** * This {@link ClientResponseFilter} implementation detects http status codes and throws {@link DockerException}s * - * @author marcus + * @author Marcus Linke * */ public class ResponseStatusExceptionFilter implements ClientResponseFilter { diff --git a/src/main/java/com/github/dockerjava/jaxrs/util/WrappedResponseInputStream.java b/src/main/java/com/github/dockerjava/jaxrs/util/WrappedResponseInputStream.java index 05d4f9066..14072ba55 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/util/WrappedResponseInputStream.java +++ b/src/main/java/com/github/dockerjava/jaxrs/util/WrappedResponseInputStream.java @@ -10,7 +10,7 @@ * {@link WrappedResponseInputStream} is closed it closes the underlying {@link Response} object also to prevent * blocking/hanging connections. * - * @author marcus + * @author Marcus Linke */ public class WrappedResponseInputStream extends InputStream { diff --git a/src/main/java/com/github/dockerjava/netty/ChannelProvider.java b/src/main/java/com/github/dockerjava/netty/ChannelProvider.java new file mode 100644 index 000000000..49cefe9d5 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/ChannelProvider.java @@ -0,0 +1,7 @@ +package com.github.dockerjava.netty; + +import io.netty.channel.Channel; + +public interface ChannelProvider { + Channel getChannel(); +} \ No newline at end of file diff --git a/src/main/java/com/github/dockerjava/netty/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/netty/DockerCmdExecFactoryImpl.java new file mode 100644 index 000000000..865389fef --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/DockerCmdExecFactoryImpl.java @@ -0,0 +1,490 @@ +package com.github.dockerjava.netty; + +import static com.google.common.base.Preconditions.checkNotNull; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.EpollDomainSocketChannel; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.channel.unix.DomainSocketAddress; +import io.netty.channel.unix.UnixChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.ssl.SslHandler; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Security; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import com.github.dockerjava.api.command.AttachContainerCmd; +import com.github.dockerjava.api.command.AuthCmd; +import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.command.CommitCmd; +import com.github.dockerjava.api.command.ContainerDiffCmd; +import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; +import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; +import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateImageCmd; +import com.github.dockerjava.api.command.DockerCmdExecFactory; +import com.github.dockerjava.api.command.EventsCmd; +import com.github.dockerjava.api.command.ExecCreateCmd; +import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.command.InfoCmd; +import com.github.dockerjava.api.command.InspectContainerCmd; +import com.github.dockerjava.api.command.InspectExecCmd; +import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.KillContainerCmd; +import com.github.dockerjava.api.command.ListContainersCmd; +import com.github.dockerjava.api.command.ListImagesCmd; +import com.github.dockerjava.api.command.LogContainerCmd; +import com.github.dockerjava.api.command.PauseContainerCmd; +import com.github.dockerjava.api.command.PingCmd; +import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.api.command.RemoveImageCmd; +import com.github.dockerjava.api.command.RestartContainerCmd; +import com.github.dockerjava.api.command.SaveImageCmd; +import com.github.dockerjava.api.command.SearchImagesCmd; +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.api.command.StatsCmd; +import com.github.dockerjava.api.command.StopContainerCmd; +import com.github.dockerjava.api.command.TagImageCmd; +import com.github.dockerjava.api.command.TopContainerCmd; +import com.github.dockerjava.api.command.UnpauseContainerCmd; +import com.github.dockerjava.api.command.VersionCmd; +import com.github.dockerjava.api.command.WaitContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.netty.exec.AttachContainerCmdExec; +import com.github.dockerjava.netty.exec.AuthCmdExec; +import com.github.dockerjava.netty.exec.BuildImageCmdExec; +import com.github.dockerjava.netty.exec.CommitCmdExec; +import com.github.dockerjava.netty.exec.ContainerDiffCmdExec; +import com.github.dockerjava.netty.exec.CopyArchiveFromContainerCmdExec; +import com.github.dockerjava.netty.exec.CopyArchiveToContainerCmdExec; +import com.github.dockerjava.netty.exec.CopyFileFromContainerCmdExec; +import com.github.dockerjava.netty.exec.CreateContainerCmdExec; +import com.github.dockerjava.netty.exec.CreateImageCmdExec; +import com.github.dockerjava.netty.exec.EventsCmdExec; +import com.github.dockerjava.netty.exec.ExecCreateCmdExec; +import com.github.dockerjava.netty.exec.ExecStartCmdExec; +import com.github.dockerjava.netty.exec.InfoCmdExec; +import com.github.dockerjava.netty.exec.InspectContainerCmdExec; +import com.github.dockerjava.netty.exec.InspectExecCmdExec; +import com.github.dockerjava.netty.exec.InspectImageCmdExec; +import com.github.dockerjava.netty.exec.KillContainerCmdExec; +import com.github.dockerjava.netty.exec.ListContainersCmdExec; +import com.github.dockerjava.netty.exec.ListImagesCmdExec; +import com.github.dockerjava.netty.exec.LogContainerCmdExec; +import com.github.dockerjava.netty.exec.PauseContainerCmdExec; +import com.github.dockerjava.netty.exec.PingCmdExec; +import com.github.dockerjava.netty.exec.PullImageCmdExec; +import com.github.dockerjava.netty.exec.PushImageCmdExec; +import com.github.dockerjava.netty.exec.RemoveContainerCmdExec; +import com.github.dockerjava.netty.exec.RemoveImageCmdExec; +import com.github.dockerjava.netty.exec.RestartContainerCmdExec; +import com.github.dockerjava.netty.exec.SaveImageCmdExec; +import com.github.dockerjava.netty.exec.SearchImagesCmdExec; +import com.github.dockerjava.netty.exec.StartContainerCmdExec; +import com.github.dockerjava.netty.exec.StatsCmdExec; +import com.github.dockerjava.netty.exec.StopContainerCmdExec; +import com.github.dockerjava.netty.exec.TagImageCmdExec; +import com.github.dockerjava.netty.exec.TopContainerCmdExec; +import com.github.dockerjava.netty.exec.UnpauseContainerCmdExec; +import com.github.dockerjava.netty.exec.VersionCmdExec; +import com.github.dockerjava.netty.exec.WaitContainerCmdExec; + +/** + * Experimental implementation of {@link DockerCmdExecFactory} that supports http connection hijacking that is needed to + * pass STDIN to the container. + * + * To use it just pass an instance via {@link DockerClientImpl#withDockerCmdExecFactory(DockerCmdExecFactory)} + * + * @see https://docs.docker.com/engine/reference/api/docker_remote_api_v1.21/#attach-to-a-container + * @see https://docs.docker.com/engine/reference/api/docker_remote_api_v1.21/#exec-start + * + * + * @author Marcus Linke + */ +public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory { + + /* + * useful links: + * + * http://stackoverflow.com/questions/33296749/netty-connect-to-unix-domain-socket-failed + * http://netty.io/wiki/native-transports.html + * https://github.com/netty/netty/blob/master/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClient.java + * https://github.com/slandelle/netty-request-chunking/blob/master/src/test/java/slandelle/ChunkingTest.java + */ + + private DockerClientConfig dockerClientConfig; + + private Bootstrap bootstrap; + + private EventLoopGroup eventLoopGroup; + + private NettyInitializer nettyInitializer; + + private ChannelProvider channelProvider = new ChannelProvider() { + @Override + public Channel getChannel() { + Channel channel = connect(); + channel.pipeline().addLast(new LoggingHandler(getClass())); + return channel; + } + }; + + @Override + public void init(DockerClientConfig dockerClientConfig) { + checkNotNull(dockerClientConfig, "config was not specified"); + this.dockerClientConfig = dockerClientConfig; + + bootstrap = new Bootstrap(); + + String scheme = dockerClientConfig.getUri().getScheme(); + + if ("unix".equals(scheme)) { + nettyInitializer = new UnixDomainSocketInitializer(); + } else if (scheme.startsWith("http")) { + nettyInitializer = new InetSocketInitializer(); + } + + eventLoopGroup = nettyInitializer.init(bootstrap, dockerClientConfig); + } + + private Channel connect() { + try { + return connect(bootstrap); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private Channel connect(final Bootstrap bootstrap) throws InterruptedException { + return nettyInitializer.connect(bootstrap); + } + + private interface NettyInitializer { + EventLoopGroup init(final Bootstrap bootstrap, DockerClientConfig dockerClientConfig); + + Channel connect(final Bootstrap bootstrap) throws InterruptedException; + } + + private class UnixDomainSocketInitializer implements NettyInitializer { + @Override + public EventLoopGroup init(Bootstrap bootstrap, DockerClientConfig dockerClientConfig) { + EventLoopGroup eventLoopGroup = new EpollEventLoopGroup(); + bootstrap.group(eventLoopGroup).channel(EpollDomainSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(final UnixChannel channel) throws Exception { + channel.pipeline().addLast(new HttpClientCodec()); + } + }); + return eventLoopGroup; + } + + @Override + public Channel connect(Bootstrap bootstrap) throws InterruptedException { + return bootstrap.connect(new DomainSocketAddress("/var/run/docker.sock")).sync().channel(); + } + } + + private class InetSocketInitializer implements NettyInitializer { + @Override + public EventLoopGroup init(Bootstrap bootstrap, final DockerClientConfig dockerClientConfig) { + EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); + + InetAddress addr = InetAddress.getLoopbackAddress(); + + final SocketAddress proxyAddress = new InetSocketAddress(addr, 8008); + + Security.addProvider(new BouncyCastleProvider()); + + bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(final SocketChannel channel) throws Exception { + // channel.pipeline().addLast(new + // HttpProxyHandler(proxyAddress)); + channel.pipeline().addLast(new HttpClientCodec()); + } + }); + + return eventLoopGroup; + } + + @Override + public Channel connect(Bootstrap bootstrap) throws InterruptedException { + String host = dockerClientConfig.getUri().getHost(); + int port = dockerClientConfig.getUri().getPort(); + + if (port == -1) { + throw new RuntimeException("no port configured for " + host); + } + + Channel channel = bootstrap.connect(host, port).sync().channel(); + + if ("https".equals(dockerClientConfig.getUri().getScheme())) { + final SslHandler ssl = initSsl(dockerClientConfig); + + if (ssl != null) { + channel.pipeline().addFirst(ssl); + } + } + + return channel; + } + + private SslHandler initSsl(DockerClientConfig dockerClientConfig) { + SslHandler ssl = null; + + try { + String host = dockerClientConfig.getUri().getHost(); + int port = dockerClientConfig.getUri().getPort(); + + SSLContext sslContext = dockerClientConfig.getSslConfig().getSSLContext(); + + SSLEngine engine = sslContext.createSSLEngine(host, port); + engine.setUseClientMode(true); + engine.setSSLParameters(enableHostNameVerification(engine.getSSLParameters())); + + // in the future we may use HostnameVerifier like here: + // https://github.com/AsyncHttpClient/async-http-client/blob/1.8.x/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java#L76 + + ssl = new SslHandler(engine); + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return ssl; + } + } + + protected DockerClientConfig getDockerClientConfig() { + checkNotNull(dockerClientConfig, + "Factor not initialized, dockerClientConfig not set. You probably forgot to call init()!"); + return dockerClientConfig; + } + + public SSLParameters enableHostNameVerification(SSLParameters sslParameters) { + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + return sslParameters; + } + + @Override + public CopyArchiveFromContainerCmd.Exec createCopyArchiveFromContainerCmdExec() { + return new CopyArchiveFromContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CopyArchiveToContainerCmd.Exec createCopyArchiveToContainerCmdExec() { + return new CopyArchiveToContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public AuthCmd.Exec createAuthCmdExec() { + return new AuthCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public InfoCmd.Exec createInfoCmdExec() { + return new InfoCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public PingCmd.Exec createPingCmdExec() { + return new PingCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public VersionCmd.Exec createVersionCmdExec() { + return new VersionCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public PullImageCmd.Exec createPullImageCmdExec() { + return new PullImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public PushImageCmd.Exec createPushImageCmdExec() { + return new PushImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public SaveImageCmd.Exec createSaveImageCmdExec() { + return new SaveImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CreateImageCmd.Exec createCreateImageCmdExec() { + return new CreateImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public SearchImagesCmd.Exec createSearchImagesCmdExec() { + return new SearchImagesCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public RemoveImageCmd.Exec createRemoveImageCmdExec() { + return new RemoveImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public ListImagesCmd.Exec createListImagesCmdExec() { + return new ListImagesCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public InspectImageCmd.Exec createInspectImageCmdExec() { + return new InspectImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public ListContainersCmd.Exec createListContainersCmdExec() { + return new ListContainersCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CreateContainerCmd.Exec createCreateContainerCmdExec() { + return new CreateContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public StartContainerCmd.Exec createStartContainerCmdExec() { + return new StartContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public InspectContainerCmd.Exec createInspectContainerCmdExec() { + return new InspectContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public ExecCreateCmd.Exec createExecCmdExec() { + return new ExecCreateCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public RemoveContainerCmd.Exec createRemoveContainerCmdExec() { + return new RemoveContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public WaitContainerCmd.Exec createWaitContainerCmdExec() { + return new WaitContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public AttachContainerCmd.Exec createAttachContainerCmdExec() { + return new AttachContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public ExecStartCmd.Exec createExecStartCmdExec() { + return new ExecStartCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public InspectExecCmd.Exec createInspectExecCmdExec() { + return new InspectExecCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public LogContainerCmd.Exec createLogContainerCmdExec() { + return new LogContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CopyFileFromContainerCmd.Exec createCopyFileFromContainerCmdExec() { + return new CopyFileFromContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public StopContainerCmd.Exec createStopContainerCmdExec() { + return new StopContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public ContainerDiffCmd.Exec createContainerDiffCmdExec() { + return new ContainerDiffCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public KillContainerCmd.Exec createKillContainerCmdExec() { + return new KillContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public RestartContainerCmd.Exec createRestartContainerCmdExec() { + return new RestartContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CommitCmd.Exec createCommitCmdExec() { + return new CommitCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public BuildImageCmd.Exec createBuildImageCmdExec() { + return new BuildImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public TopContainerCmd.Exec createTopContainerCmdExec() { + return new TopContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public TagImageCmd.Exec createTagImageCmdExec() { + return new TagImageCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public PauseContainerCmd.Exec createPauseContainerCmdExec() { + return new PauseContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec() { + return new UnpauseContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public EventsCmd.Exec createEventsCmdExec() { + return new EventsCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public StatsCmd.Exec createStatsCmdExec() { + return new StatsCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public void close() throws IOException { + checkNotNull(eventLoopGroup, "Factory not initialized. You probably forgot to call init()!"); + + eventLoopGroup.shutdownGracefully(); + } + + private WebTarget getBaseResource() { + return new WebTarget(channelProvider); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/InvocationBuilder.java b/src/main/java/com/github/dockerjava/netty/InvocationBuilder.java new file mode 100644 index 000000000..a478cf6c1 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/InvocationBuilder.java @@ -0,0 +1,491 @@ +package com.github.dockerjava.netty; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpClientUpgradeHandler; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.json.JsonObjectDecoder; +import io.netty.handler.stream.ChunkedStream; +import io.netty.handler.stream.ChunkedWriteHandler; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.async.ResultCallbackTemplate; +import com.github.dockerjava.netty.handler.FramedResponseStreamHandler; +import com.github.dockerjava.netty.handler.HttpConnectionHijackHandler; +import com.github.dockerjava.netty.handler.HttpRequestProvider; +import com.github.dockerjava.netty.handler.HttpResponseHandler; +import com.github.dockerjava.netty.handler.HttpResponseStreamHandler; +import com.github.dockerjava.netty.handler.JsonResponseCallbackHandler; + +/** + * This class is basically a replacement of javax.ws.rs.client.Invocation.Builder to allow simpler + * migration of JAX-RS code to a netty based implementation. + * + * @author Marcus Linke + */ +public class InvocationBuilder { + + public class ResponseCallback extends ResultCallbackTemplate, T> { + + private T result = null; + + public T awaitResult() { + try { + awaitCompletion(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return result; + } + + @Override + public void onNext(T object) { + result = object; + } + } + + private ChannelProvider channelProvider; + + private String resource; + + private Map headers = new HashMap(); + + public InvocationBuilder(ChannelProvider channelProvider, String resource) { + this.channelProvider = channelProvider; + this.resource = resource; + } + + public InvocationBuilder accept(MediaType mediaType) { + return header(HttpHeaderNames.ACCEPT.toString(), mediaType.getMediaType()); + } + + public InvocationBuilder header(String name, String value) { + headers.put(name, value); + return this; + } + + public void delete() { + + HttpRequestProvider requestProvider = httpDeleteRequestProvider(); + + ResponseCallback callback = new ResponseCallback(); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, callback); + + Channel channel = getChannel(); + + channel.pipeline().addLast(responseHandler); + + sendRequest(requestProvider, channel); + + callback.awaitResult(); + } + + public void get(ResultCallback resultCallback) { + + HttpRequestProvider requestProvider = httpGetRequestProvider(); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + FramedResponseStreamHandler streamHandler = new FramedResponseStreamHandler(resultCallback); + + Channel channel = getChannel(); + + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(streamHandler); + + sendRequest(requestProvider, channel); + } + + public T get(TypeReference typeReference) { + + ResponseCallback callback = new ResponseCallback(); + + get(typeReference, callback); + + return callback.awaitResult(); + } + + public void get(TypeReference typeReference, ResultCallback resultCallback) { + + HttpRequestProvider requestProvider = httpGetRequestProvider(); + + Channel channel = getChannel(); + + initCallback(channel, resultCallback); + + JsonResponseCallbackHandler jsonResponseHandler = new JsonResponseCallbackHandler(typeReference, + resultCallback); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(new JsonObjectDecoder()); + channel.pipeline().addLast(jsonResponseHandler); + + sendRequest(requestProvider, channel); + + return; + } + + private Channel getChannel() { + return channelProvider.getChannel(); + } + + private HttpRequestProvider httpDeleteRequestProvider() { + return new HttpRequestProvider() { + @Override + public HttpRequest getHttpRequest(String uri) { + return prepareDeleteRequest(uri); + } + }; + } + + private HttpRequestProvider httpGetRequestProvider() { + return new HttpRequestProvider() { + @Override + public HttpRequest getHttpRequest(String uri) { + return prepareGetRequest(uri); + } + }; + } + + private HttpRequestProvider httpPostRequestProvider(final Object entity) { + return new HttpRequestProvider() { + @Override + public HttpRequest getHttpRequest(String uri) { + return preparePostRequest(uri, entity); + } + }; + } + + private HttpRequestProvider httpPutRequestProvider(final Object entity) { + return new HttpRequestProvider() { + @Override + public HttpRequest getHttpRequest(String uri) { + return preparePutRequest(uri, entity); + } + }; + } + + public InputStream post(final Object entity) { + + HttpRequestProvider requestProvider = httpPostRequestProvider(entity); + + Channel channel = getChannel(); + + ResponseCallback callback = new ResponseCallback(); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, callback); + HttpResponseStreamHandler streamHandler = new HttpResponseStreamHandler(callback); + + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(streamHandler); + + sendRequest(requestProvider, channel); + + return callback.awaitResult(); + } + + public void post(final Object entity, final InputStream stdin, ResultCallback resultCallback) { + + HttpRequestProvider requestProvider = httpPostRequestProvider(entity); + + FramedResponseStreamHandler streamHandler = new FramedResponseStreamHandler(resultCallback); + + final Channel channel = getChannel(); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + HttpConnectionHijackHandler hijackHandler = new HttpConnectionHijackHandler(responseHandler); + + channel.pipeline().addLast( + new HttpClientUpgradeHandler(new HttpClientCodec(), hijackHandler, Integer.MAX_VALUE)); + channel.pipeline().addLast(streamHandler); + + sendRequest(requestProvider, channel); + + // wait for successful http upgrade procedure + hijackHandler.awaitUpgrade(); + + // now we can start a new thread that reads from stdin and writes to the channel + new Thread(new Runnable() { + + private int read(BufferedReader reader) { + try { + return reader.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void run() { + + BufferedReader reader = new BufferedReader(new InputStreamReader(stdin, Charset.forName("UTF-8"))); + + int read = -1; + while ((read = read(reader)) != -1) { + byte[] bytes = ByteBuffer.allocate(4).putInt(read).array(); + try { + bytes = new String(bytes).getBytes("US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + channel.writeAndFlush(Unpooled.copiedBuffer(bytes)); + } + } + }).start(); + } + + public T post(final Object entity, TypeReference typeReference) { + + ResponseCallback callback = new ResponseCallback(); + + post(entity, typeReference, callback); + + return callback.awaitResult(); + } + + public void post(final Object entity, TypeReference typeReference, final ResultCallback resultCallback) { + + HttpRequestProvider requestProvider = httpPostRequestProvider(entity); + + Channel channel = getChannel(); + + initCallback(channel, resultCallback); + + JsonResponseCallbackHandler jsonResponseHandler = new JsonResponseCallbackHandler(typeReference, + resultCallback); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(new JsonObjectDecoder()); + channel.pipeline().addLast(jsonResponseHandler); + + sendRequest(requestProvider, channel); + + return; + } + + private void initCallback(final Channel channel, final ResultCallback resultCallback) { + Closeable closeable = new Closeable() { + @Override + public void close() throws IOException { + try { + channel.close().sync(); + } catch (InterruptedException e) { + resultCallback.onError(e); + } + } + }; + + resultCallback.onStart(closeable); + } + + private HttpRequest prepareDeleteRequest(String uri) { + + FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.DELETE, uri); + + setDefaultHeaders(request); + + return request; + } + + private FullHttpRequest prepareGetRequest(String uri) { + + FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri); + + setDefaultHeaders(request); + + return request; + } + + private HttpRequest preparePostRequest(String uri, Object entity) { + return prepareEntityRequest(uri, entity, HttpMethod.POST); + } + + private HttpRequest preparePutRequest(String uri, Object entity) { + return prepareEntityRequest(uri, entity, HttpMethod.PUT); + } + + private HttpRequest prepareEntityRequest(String uri, Object entity, HttpMethod httpMethod) { + + HttpRequest request = null; + + if (entity != null) { + + FullHttpRequest fullRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, httpMethod, uri); + + byte[] bytes; + try { + bytes = new ObjectMapper().writeValueAsBytes(entity); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + fullRequest.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json"); + fullRequest.content().clear().writeBytes(Unpooled.copiedBuffer(bytes)); + fullRequest.headers().set(HttpHeaderNames.CONTENT_LENGTH, bytes.length); + + request = fullRequest; + } else { + request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, httpMethod, uri); + request.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0); + } + + setDefaultHeaders(request); + + return request; + } + + private void sendRequest(HttpRequestProvider requestProvider, Channel channel) { + + ChannelFuture channelFuture = channel.writeAndFlush(requestProvider.getHttpRequest(resource)); + + channelFuture.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + System.err.println("Request success"); + } + + } + }); + } + + private void setDefaultHeaders(HttpRequest request) { + request.headers().set(HttpHeaderNames.HOST, ""); + request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + request.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP); + + for (Map.Entry entry : headers.entrySet()) { + request.headers().set((CharSequence) entry.getKey(), entry.getValue()); + } + } + + public T post(TypeReference typeReference, InputStream body) { + + ResponseCallback callback = new ResponseCallback(); + + post(typeReference, callback, body); + + return callback.awaitResult(); + } + + + public void post(TypeReference typeReference, ResultCallback resultCallback, InputStream body) { + HttpRequestProvider requestProvider = httpPostRequestProvider(null); + + Channel channel = getChannel(); + + initCallback(channel, resultCallback); + + JsonResponseCallbackHandler jsonResponseHandler = new JsonResponseCallbackHandler(typeReference, + resultCallback); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + channel.pipeline().addLast(new ChunkedWriteHandler()); + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(new JsonObjectDecoder()); + channel.pipeline().addLast(jsonResponseHandler); + + HttpRequest request = requestProvider.getHttpRequest(resource); + + // don't accept FullHttpRequest here + if (request instanceof FullHttpRequest) { + throw new DockerClientException("fatal: request is instance of FullHttpRequest"); + } + + request.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + request.headers().remove(HttpHeaderNames.CONTENT_LENGTH); + + channel.write(request); + + channel.write(new ChunkedStream(new BufferedInputStream(body, 1024 * 1024), 1024 * 1024)); + channel.write(LastHttpContent.EMPTY_LAST_CONTENT); + channel.flush(); + } + + public InputStream get() { + HttpRequestProvider requestProvider = httpGetRequestProvider(); + + Channel channel = getChannel(); + + ResponseCallback resultCallback = new ResponseCallback(); + + initCallback(channel, resultCallback); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + HttpResponseStreamHandler streamHandler = new HttpResponseStreamHandler(resultCallback); + + channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(streamHandler); + + sendRequest(requestProvider, channel); + + return resultCallback.awaitResult(); + } + + public void put(InputStream body, MediaType mediaType) { + HttpRequestProvider requestProvider = httpPutRequestProvider(null); + + Channel channel = getChannel(); + + ResponseCallback resultCallback = new ResponseCallback(); + + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + + channel.pipeline().addLast(new ChunkedWriteHandler()); + channel.pipeline().addLast(responseHandler); + + HttpRequest request = requestProvider.getHttpRequest(resource); + + // don't accept FullHttpRequest here + if (request instanceof FullHttpRequest) { + throw new DockerClientException("fatal: request is instance of FullHttpRequest"); + } + + request.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + request.headers().remove(HttpHeaderNames.CONTENT_LENGTH); + request.headers().set(HttpHeaderNames.CONTENT_TYPE, mediaType.getMediaType()); + + channel.write(request); + channel.write(new ChunkedStream(new BufferedInputStream(body, 1024 * 1024))); + channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); + + resultCallback.awaitResult(); + }; +} diff --git a/src/main/java/com/github/dockerjava/netty/MediaType.java b/src/main/java/com/github/dockerjava/netty/MediaType.java new file mode 100644 index 000000000..a7738604a --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/MediaType.java @@ -0,0 +1,24 @@ +package com.github.dockerjava.netty; + +/** + * This class is basically a replacement of javax.ws.rs.core.MediaType to allow simpler + * migration of JAX-RS code to a netty based implementation. + * + * @author Marcus Linke + */ +public enum MediaType { + + APPLICATION_JSON("application/json"), + APPLICATION_OCTET_STREAM("application/octet-stream"), + APPLICATION_X_TAR("application/x-tar"); + + private String mediaType; + + private MediaType(String mediaType) { + this.mediaType = mediaType; + } + + public String getMediaType() { + return mediaType; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/WebTarget.java b/src/main/java/com/github/dockerjava/netty/WebTarget.java new file mode 100644 index 000000000..7698858a3 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/WebTarget.java @@ -0,0 +1,73 @@ +package com.github.dockerjava.netty; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; + +/** + * This class is basically a replacement of javax.ws.rs.client.WebTarget to allow simpler + * migration of JAX-RS code to a netty based implementation. + * + * @author Marcus Linke + */ +public class WebTarget { + + private ChannelProvider channelProvider; + + private List path = new ArrayList(); + + private Map queryParams = new HashMap(); + + private static String PATH_SEPARATOR = "/"; + + public WebTarget(ChannelProvider channelProvider) { + this.channelProvider = channelProvider; + } + + public WebTarget path(String... components) { + + for (String component : components) { + + path.addAll(Arrays.asList(StringUtils.split(component, PATH_SEPARATOR))); + } + + return this; + } + + public InvocationBuilder request() { + String resource = PATH_SEPARATOR + StringUtils.join(path, PATH_SEPARATOR); + + List params = new ArrayList(); + for (Map.Entry entry : queryParams.entrySet()) { + params.add(entry.getKey() + "=" + entry.getValue()); + } + + if (!params.isEmpty()) { + resource = resource + "?" + StringUtils.join(params, "&"); + } + + return new InvocationBuilder(channelProvider, resource); + } + + public WebTarget resolveTemplate(String name, Object value) { + List newPath = new ArrayList(); + for (String component : path) { + component = component.replaceAll("\\{" + name + "\\}", value.toString()); + newPath.add(component); + } + path = newPath; + return this; + } + + public WebTarget queryParam(String name, Object value) { + if (value != null) { + queryParams.put(name, value.toString()); + } + return this; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/AbstrAsyncDockerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/AbstrAsyncDockerCmdExec.java new file mode 100644 index 000000000..3d1d4fac3 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/AbstrAsyncDockerCmdExec.java @@ -0,0 +1,63 @@ +package com.github.dockerjava.netty.exec; + +import java.io.Closeable; +import java.io.IOException; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.AsyncDockerCmd; +import com.github.dockerjava.api.command.DockerCmdAsyncExec; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public abstract class AbstrAsyncDockerCmdExec, A_RES_T> extends + AbstrDockerCmdExec implements DockerCmdAsyncExec { + + public AbstrAsyncDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + public Void exec(CMD_T command, ResultCallback resultCallback) { + return execute(command, resultCallback); + } + + protected final Void execute(final CMD_T command, final ResultCallback resultCallback) { + + ResultCallback delegatingResultCallback = new ResultCallback() { + + @Override + public void close() throws IOException { + resultCallback.close(); + command.close(); + } + + @Override + public void onStart(Closeable closeable) { + resultCallback.onStart(closeable); + } + + @Override + public void onNext(A_RES_T object) { + resultCallback.onNext(object); + } + + @Override + public void onError(Throwable throwable) { + resultCallback.onError(throwable); + } + + @Override + public void onComplete() { + resultCallback.onComplete(); + command.close(); + } + }; + + execute0(command, delegatingResultCallback); + + return null; + } + + protected abstract Void execute0(final CMD_T command, final ResultCallback resultCallback); + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/AbstrDockerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/AbstrDockerCmdExec.java new file mode 100644 index 000000000..e8b3597c9 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/AbstrDockerCmdExec.java @@ -0,0 +1,72 @@ +package com.github.dockerjava.netty.exec; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.IOException; + +import org.apache.commons.codec.binary.Base64; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.RemoteApiVersion; +import com.github.dockerjava.netty.WebTarget; + +public abstract class AbstrDockerCmdExec { + + private final DockerClientConfig dockerClientConfig; + + private final WebTarget baseResource; + + public AbstrDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + checkNotNull(baseResource, "baseResource was not specified"); + checkNotNull(dockerClientConfig, "dockerClientConfig was not specified"); + this.baseResource = baseResource; + this.dockerClientConfig = dockerClientConfig; + } + + protected WebTarget getBaseResource() { + return baseResource; + } + + protected AuthConfigurations getBuildAuthConfigs() { + return dockerClientConfig.getAuthConfigurations(); + } + + protected String registryAuth(AuthConfig authConfig) { + try { + return Base64.encodeBase64String(new ObjectMapper().writeValueAsString(authConfig).getBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected String registryConfigs(AuthConfigurations authConfigs) { + try { + final String json; + if (dockerClientConfig.getVersion().isGreaterOrEqual(RemoteApiVersion.VERSION_1_19)) { + json = new ObjectMapper().writeValueAsString(authConfigs.getConfigs()); + } else { + json = new ObjectMapper().writeValueAsString(authConfigs); + } + + return Base64.encodeBase64String(json.getBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected boolean bool(Boolean bool) { + return bool != null && bool; + } + + protected WebTarget booleanQueryParam(WebTarget webTarget, String name, Boolean value) { + if (bool(value)) { + webTarget = webTarget.queryParam(name, bool(value) + ""); + } + + return webTarget; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/AbstrSyncDockerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/AbstrSyncDockerCmdExec.java new file mode 100644 index 000000000..0422110a5 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/AbstrSyncDockerCmdExec.java @@ -0,0 +1,34 @@ +package com.github.dockerjava.netty.exec; + +import com.github.dockerjava.api.command.DockerCmd; +import com.github.dockerjava.api.command.DockerCmdSyncExec; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + + +public abstract class AbstrSyncDockerCmdExec, RES_T> extends AbstrDockerCmdExec + implements DockerCmdSyncExec { + + public AbstrSyncDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + public RES_T exec(CMD_T command) { + // this hack works because of ResponseStatusExceptionFilter + try (CMD_T cmd = command) { + try { + return execute(cmd); + } catch (RuntimeException e) { + if (e.getCause() instanceof DockerException) { + throw (DockerException) e.getCause(); + } else { + throw e; + } + } + } + } + + protected abstract RES_T execute(CMD_T command); +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/AttachContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/AttachContainerCmdExec.java new file mode 100644 index 000000000..2fdace48a --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/AttachContainerCmdExec.java @@ -0,0 +1,39 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.AttachContainerCmd; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class AttachContainerCmdExec extends AbstrAsyncDockerCmdExec implements + AttachContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(AttachContainerCmdExec.class); + + public AttachContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(AttachContainerCmd command, ResultCallback resultCallback) { + + WebTarget webTarget = getBaseResource().path("/containers/{id}/attach").resolveTemplate("id", + command.getContainerId()); + + webTarget = booleanQueryParam(webTarget, "logs", command.hasLogsEnabled()); + webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled()); + webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled()); + webTarget = booleanQueryParam(webTarget, "stdin", command.getStdin() != null); + webTarget = booleanQueryParam(webTarget, "stream", command.hasFollowStreamEnabled()); + + LOGGER.trace("POST: {}", webTarget); + + webTarget.request().post(null, command.getStdin(), resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/AuthCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/AuthCmdExec.java new file mode 100644 index 000000000..b6f004940 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/AuthCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.AuthCmd; +import com.github.dockerjava.api.model.AuthResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class AuthCmdExec extends AbstrSyncDockerCmdExec implements AuthCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(AuthCmdExec.class); + + public AuthCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected AuthResponse execute(AuthCmd command) { + WebTarget webResource = getBaseResource().path("/auth"); + LOGGER.trace("POST: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON) + .post(command.getAuthConfig(), new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java new file mode 100644 index 000000000..9c0e6c09f --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java @@ -0,0 +1,93 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.BuildResponseItem; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.InvocationBuilder; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class BuildImageCmdExec extends AbstrAsyncDockerCmdExec implements + BuildImageCmd.Exec { + private static final Logger LOGGER = LoggerFactory.getLogger(BuildImageCmdExec.class); + + public BuildImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + private InvocationBuilder resourceWithOptionalAuthConfig(BuildImageCmd command, InvocationBuilder request) { + final AuthConfigurations authConfigs = firstNonNull(command.getBuildAuthConfigs(), getBuildAuthConfigs()); + if (authConfigs != null) { + request = request.header("X-Registry-Config", registryConfigs(authConfigs)); + } + return request; + } + + private static AuthConfigurations firstNonNull(final AuthConfigurations fromCommand, + final AuthConfigurations fromConfig) { + if (fromCommand != null) { + return fromCommand; + } + if (fromConfig != null) { + return fromConfig; + } + return null; + } + + @Override + protected Void execute0(BuildImageCmd command, ResultCallback resultCallback) { + + WebTarget webTarget = getBaseResource().path("/build"); + String dockerFilePath = command.getPathToDockerfile(); + + if (dockerFilePath != null && command.getRemote() == null && !"Dockerfile".equals(dockerFilePath)) { + webTarget = webTarget.queryParam("dockerfile", dockerFilePath); + } + if (command.getTag() != null) { + webTarget = webTarget.queryParam("t", command.getTag()); + } + if (command.getRemote() != null) { + webTarget = webTarget.queryParam("remote", command.getRemote().toString()); + } + + webTarget = booleanQueryParam(webTarget, "q", command.isQuiet()); + webTarget = booleanQueryParam(webTarget, "nocache", command.hasNoCacheEnabled()); + webTarget = booleanQueryParam(webTarget, "pull", command.hasPullEnabled()); + webTarget = booleanQueryParam(webTarget, "rm", command.hasRemoveEnabled()); + webTarget = booleanQueryParam(webTarget, "forcerm", command.isForcerm()); + + // this has to be handled differently as it should switch to 'false' + if (command.hasRemoveEnabled() == null || !command.hasRemoveEnabled()) { + webTarget = webTarget.queryParam("rm", "false"); + } + + if (command.getMemory() != null) { + webTarget = webTarget.queryParam("memory", command.getMemory()); + } + if (command.getMemswap() != null) { + webTarget = webTarget.queryParam("memswap", command.getMemswap()); + } + if (command.getCpushares() != null) { + webTarget = webTarget.queryParam("cpushares", command.getCpushares()); + } + if (command.getCpusetcpus() != null) { + webTarget = webTarget.queryParam("cpusetcpus", command.getCpusetcpus()); + } + + LOGGER.trace("POST: {}", webTarget); + + InvocationBuilder builder = resourceWithOptionalAuthConfig(command, webTarget.request()).accept( + MediaType.APPLICATION_JSON).header("Content-Type", "application/tar").header("encoding", "gzip"); + + builder.post(new TypeReference() { + }, resultCallback, command.getTarInputStream()); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CommitCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CommitCmdExec.java new file mode 100644 index 000000000..b42bbdb3b --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CommitCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.dockerjava.api.command.CommitCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CommitCmdExec extends AbstrSyncDockerCmdExec implements CommitCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommitCmdExec.class); + + public CommitCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected String execute(CommitCmd command) { + WebTarget webTarget = getBaseResource().path("/commit").queryParam("container", command.getContainerId()) + .queryParam("repo", command.getRepository()).queryParam("tag", command.getTag()) + .queryParam("m", command.getMessage()).queryParam("author", command.getAuthor()); + + webTarget = booleanQueryParam(webTarget, "pause", command.hasPauseEnabled()); + + LOGGER.trace("POST: {}", webTarget); + ObjectNode objectNode = webTarget.request().accept(MediaType.APPLICATION_JSON). + post(command, new TypeReference() {}); + + return objectNode.get("Id").asText(); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExec.java new file mode 100644 index 000000000..662b9c1d4 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExec.java @@ -0,0 +1,34 @@ +package com.github.dockerjava.netty.exec; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ContainerDiffCmd; +import com.github.dockerjava.api.model.ChangeLog; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class ContainerDiffCmdExec extends AbstrSyncDockerCmdExec> implements + ContainerDiffCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ContainerDiffCmdExec.class); + + public ContainerDiffCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + 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 TypeReference>() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExec.java new file mode 100644 index 000000000..6f4a93ba3 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExec.java @@ -0,0 +1,32 @@ +package com.github.dockerjava.netty.exec; + +import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CopyArchiveFromContainerCmdExec extends AbstrSyncDockerCmdExec + implements CopyArchiveFromContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CopyArchiveFromContainerCmdExec.class); + + public CopyArchiveFromContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InputStream execute(CopyArchiveFromContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/archive").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("Get: " + webResource.toString()); + + return webResource.queryParam("path", command.getResource()).request().accept(MediaType.APPLICATION_X_TAR) + .get(); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExec.java new file mode 100644 index 000000000..c956a815d --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CopyArchiveToContainerCmdExec extends AbstrSyncDockerCmdExec implements + CopyArchiveToContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CopyArchiveFromContainerCmdExec.class); + + public CopyArchiveToContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(CopyArchiveToContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/archive").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("PUT: " + webResource.toString()); + InputStream streamToUpload = command.getTarInputStream(); + + webResource.queryParam("path", command.getRemotePath()) + .queryParam("noOverwriteDirNonDir", command.isNoOverwriteDirNonDir()).request() + .put(streamToUpload, MediaType.APPLICATION_X_TAR); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExec.java new file mode 100644 index 000000000..338b9b973 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CopyFileFromContainerCmdExec extends AbstrSyncDockerCmdExec + implements CopyFileFromContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CopyFileFromContainerCmdExec.class); + + public CopyFileFromContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InputStream execute(CopyFileFromContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/copy").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: " + webResource.toString()); + + return webResource.request().accept(MediaType.APPLICATION_OCTET_STREAM) + .post(command); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CreateContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CreateContainerCmdExec.java new file mode 100644 index 000000000..f7e4e39d9 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CreateContainerCmdExec.java @@ -0,0 +1,35 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CreateContainerCmdExec extends AbstrSyncDockerCmdExec + implements CreateContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CreateContainerCmdExec.class); + + public CreateContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected CreateContainerResponse execute(CreateContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/create"); + + if (command.getName() != null) { + webResource = webResource.queryParam("name", command.getName()); + } + + LOGGER.trace("POST: {} ", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON) + .post(command, new TypeReference() { + }); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/CreateImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/CreateImageCmdExec.java new file mode 100644 index 000000000..3d3ddec27 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/CreateImageCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.CreateImageCmd; +import com.github.dockerjava.api.command.CreateImageResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class CreateImageCmdExec extends AbstrSyncDockerCmdExec implements + CreateImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CreateImageCmdExec.class); + + public CreateImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected CreateImageResponse execute(CreateImageCmd command) { + WebTarget webResource = getBaseResource().path("/images/create").queryParam("repo", command.getRepository()) + .queryParam("tag", command.getTag()).queryParam("fromSrc", "-"); + + LOGGER.trace("POST: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_OCTET_STREAM) + .post(new TypeReference() {}, command.getImageStream()); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/EventsCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/EventsCmdExec.java new file mode 100644 index 000000000..be1ac0956 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/EventsCmdExec.java @@ -0,0 +1,41 @@ +package com.github.dockerjava.netty.exec; + +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.EventsCmd; +import com.github.dockerjava.api.model.Event; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class EventsCmdExec extends AbstrAsyncDockerCmdExec implements EventsCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(EventsCmdExec.class); + + public EventsCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(EventsCmd command, ResultCallback resultCallback) { + + WebTarget webTarget = getBaseResource().path("/events").queryParam("since", command.getSince()) + .queryParam("until", command.getUntil()); + + if (command.getFilters() != null) { + webTarget = webTarget + .queryParam("filters", urlPathSegmentEscaper().escape(command.getFilters().toString())); + } + + LOGGER.trace("GET: {}", webTarget); + + webTarget.request().get(new TypeReference() { + }, resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/ExecCreateCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/ExecCreateCmdExec.java new file mode 100644 index 000000000..1535cfe4f --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/ExecCreateCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ExecCreateCmd; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class ExecCreateCmdExec extends AbstrSyncDockerCmdExec implements + ExecCreateCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExecCreateCmdExec.class); + + public ExecCreateCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected ExecCreateCmdResponse execute(ExecCreateCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/exec").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: {}", webResource); + + return webResource.request().accept(MediaType.APPLICATION_JSON) + .post(command, new TypeReference() { + }); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/ExecStartCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/ExecStartCmdExec.java new file mode 100644 index 000000000..374b2062d --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/ExecStartCmdExec.java @@ -0,0 +1,29 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class ExecStartCmdExec extends AbstrAsyncDockerCmdExec implements ExecStartCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExecStartCmdExec.class); + + public ExecStartCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(ExecStartCmd command, ResultCallback resultCallback) { + WebTarget webTarget = getBaseResource().path("/exec/{id}/start").resolveTemplate("id", command.getExecId()); + + webTarget.request().accept(MediaType.APPLICATION_JSON).post(command, command.getStdin(), resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/InfoCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/InfoCmdExec.java new file mode 100644 index 000000000..288765650 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/InfoCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.InfoCmd; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +/** + * http://stackoverflow.com/questions/33296749/netty-connect-to-unix-domain- socket-failed + * http://netty.io/wiki/native-transports.html + * https://github.com/netty/netty/blob/master/example/src/main/java/io/netty/ example/http/snoop/HttpSnoopClient.java + * + * @author Marcus Linke + * + */ +public class InfoCmdExec implements InfoCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(InfoCmdExec.class); + + private WebTarget webResource; + + public InfoCmdExec(WebTarget webResource, DockerClientConfig dockerClientConfig) { + this.webResource = webResource; + } + + @Override + public Info exec(InfoCmd command) { + return webResource.path("info").request().get(new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/InspectContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/InspectContainerCmdExec.java new file mode 100644 index 000000000..e8f691ba1 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/InspectContainerCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.InspectContainerCmd; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class InspectContainerCmdExec extends AbstrSyncDockerCmdExec + implements InspectContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(InspectContainerCmdExec.class); + + public InspectContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InspectContainerResponse execute(InspectContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/json").resolveTemplate("id", + command.getContainerId()); + + LOGGER.debug("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON) + .get(new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/InspectExecCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/InspectExecCmdExec.java new file mode 100644 index 000000000..ee913f369 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/InspectExecCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.InspectExecCmd; +import com.github.dockerjava.api.command.InspectExecResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class InspectExecCmdExec extends AbstrSyncDockerCmdExec implements + InspectExecCmd.Exec { + private static final Logger LOGGER = LoggerFactory.getLogger(InspectExecCmdExec.class); + + public InspectExecCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InspectExecResponse execute(InspectExecCmd command) { + WebTarget webResource = getBaseResource().path("/exec/{id}/json").resolveTemplate("id", command.getExecId()); + + LOGGER.debug("GET: {}", webResource); + + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference() { + }); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/InspectImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/InspectImageCmdExec.java new file mode 100644 index 000000000..b86072ecb --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/InspectImageCmdExec.java @@ -0,0 +1,32 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class InspectImageCmdExec extends AbstrSyncDockerCmdExec implements + InspectImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(InspectImageCmdExec.class); + + public InspectImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InspectImageResponse execute(InspectImageCmd command) { + WebTarget webResource = getBaseResource().path("/images/{id}/json").resolveTemplate("id", command.getImageId()); + + LOGGER.trace("GET: {}", webResource); + + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/KillContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/KillContainerCmdExec.java new file mode 100644 index 000000000..b81f6449f --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/KillContainerCmdExec.java @@ -0,0 +1,35 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.KillContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class KillContainerCmdExec extends AbstrSyncDockerCmdExec implements + KillContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(KillContainerCmdExec.class); + + public KillContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(KillContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/kill").resolveTemplate("id", + command.getContainerId()); + + if (command.getSignal() != null) { + webResource = webResource.queryParam("signal", command.getSignal()); + } + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/ListContainersCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/ListContainersCmdExec.java new file mode 100644 index 000000000..b45e76cbd --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/ListContainersCmdExec.java @@ -0,0 +1,54 @@ +package com.github.dockerjava.netty.exec; + +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ListContainersCmd; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class ListContainersCmdExec extends AbstrSyncDockerCmdExec> implements + ListContainersCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ListContainersCmdExec.class); + + public ListContainersCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected List execute(ListContainersCmd command) { + WebTarget webTarget = getBaseResource().path("/containers/json").queryParam("since", command.getSinceId()) + .queryParam("before", command.getBeforeId()); + + webTarget = booleanQueryParam(webTarget, "all", command.hasShowAllEnabled()); + webTarget = booleanQueryParam(webTarget, "size", command.hasShowSizeEnabled()); + + if (command.getLimit() != null && command.getLimit() >= 0) { + webTarget = webTarget.queryParam("limit", String.valueOf(command.getLimit())); + } + + if (command.getFilters() != null) { + webTarget = webTarget + .queryParam("filters", urlPathSegmentEscaper().escape(command.getFilters().toString())); + } + + LOGGER.trace("GET: {}", webTarget); + + List containers = webTarget.request().accept(MediaType.APPLICATION_JSON) + .get(new TypeReference>() { + }); + + LOGGER.trace("Response: {}", containers); + + return containers; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/ListImagesCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/ListImagesCmdExec.java new file mode 100644 index 000000000..4ca65a061 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/ListImagesCmdExec.java @@ -0,0 +1,45 @@ +package com.github.dockerjava.netty.exec; + +import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ListImagesCmd; +import com.github.dockerjava.api.model.Image; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class ListImagesCmdExec extends AbstrSyncDockerCmdExec> implements ListImagesCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ListImagesCmdExec.class); + + public ListImagesCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected List execute(ListImagesCmd command) { + WebTarget webTarget = getBaseResource().path("/images/json"); + + webTarget = booleanQueryParam(webTarget, "all", command.hasShowAllEnabled()); + + if (command.getFilters() != null) { + webTarget = webTarget.queryParam("filters", urlPathSegmentEscaper().escape(command.getFilters())); + } + + LOGGER.trace("GET: {}", webTarget); + + List images = webTarget.request().accept(MediaType.APPLICATION_JSON) + .get(new TypeReference>() { + }); + + LOGGER.trace("Response: {}", images); + + return images; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/LogContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/LogContainerCmdExec.java new file mode 100644 index 000000000..911780362 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/LogContainerCmdExec.java @@ -0,0 +1,47 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.LogContainerCmd; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + + +public class LogContainerCmdExec extends AbstrAsyncDockerCmdExec implements + LogContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(LogContainerCmdExec.class); + + public LogContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(LogContainerCmd command, ResultCallback resultCallback) { + + WebTarget webTarget = getBaseResource().path("/containers/{id}/logs").resolveTemplate("id", + command.getContainerId()); + + if (command.getTail() != null) { + webTarget = webTarget.queryParam("tail", command.getTail()); + } + + if (command.getSince() != null) { + webTarget = webTarget.queryParam("since", command.getSince()); + } + + webTarget = booleanQueryParam(webTarget, "timestamps", command.hasTimestampsEnabled()); + webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled()); + webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled()); + webTarget = booleanQueryParam(webTarget, "follow", command.hasFollowStreamEnabled()); + + LOGGER.trace("GET: {}", webTarget); + + webTarget.request().get(resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/PauseContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/PauseContainerCmdExec.java new file mode 100644 index 000000000..5d8443190 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/PauseContainerCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.PauseContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class PauseContainerCmdExec extends AbstrSyncDockerCmdExec implements + PauseContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(PauseContainerCmdExec.class); + + public PauseContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(PauseContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/pause").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/PingCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/PingCmdExec.java new file mode 100644 index 000000000..1302c9730 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/PingCmdExec.java @@ -0,0 +1,28 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.PingCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class PingCmdExec extends AbstrSyncDockerCmdExec implements PingCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(PingCmdExec.class); + + public PingCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(PingCmd command) { + WebTarget webResource = getBaseResource().path("/_ping"); + + LOGGER.trace("GET: {}", webResource); + webResource.request().get(); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/PullImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/PullImageCmdExec.java new file mode 100644 index 000000000..7f15b4e62 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/PullImageCmdExec.java @@ -0,0 +1,46 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.PullResponseItem; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.InvocationBuilder; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class PullImageCmdExec extends AbstrAsyncDockerCmdExec implements + PullImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(PullImageCmdExec.class); + + public PullImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + private InvocationBuilder resourceWithOptionalAuthConfig(PullImageCmd command, InvocationBuilder request) { + AuthConfig authConfig = command.getAuthConfig(); + if (authConfig != null) { + request = request.header("X-Registry-Auth", registryAuth(authConfig)); + } + return request; + } + + @Override + protected Void execute0(PullImageCmd command, ResultCallback resultCallback) { + + WebTarget webResource = getBaseResource().path("/images/create").queryParam("tag", command.getTag()) + .queryParam("fromImage", command.getRepository()).queryParam("registry", command.getRegistry()); + + LOGGER.trace("POST: {}", webResource); + resourceWithOptionalAuthConfig(command, webResource.request()).accept(MediaType.APPLICATION_OCTET_STREAM).post( + null, new TypeReference() { + }, resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/PushImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/PushImageCmdExec.java new file mode 100644 index 000000000..d6dcdbd00 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/PushImageCmdExec.java @@ -0,0 +1,48 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.PushResponseItem; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.InvocationBuilder; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class PushImageCmdExec extends AbstrAsyncDockerCmdExec implements + PushImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(PushImageCmdExec.class); + + public PushImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + private String name(PushImageCmd command) { + String name = command.getName(); + AuthConfig authConfig = command.getAuthConfig(); + return (name.contains("/") || authConfig == null) ? name : authConfig.getUsername(); + } + + @Override + protected Void execute0(PushImageCmd command, ResultCallback resultCallback) { + + WebTarget webResource = getBaseResource().path("/images/" + name(command) + "/push").queryParam("tag", + command.getTag()); + + final String registryAuth = registryAuth(command.getAuthConfig()); + LOGGER.trace("POST: {}", webResource); + + InvocationBuilder builder = webResource.request().header("X-Registry-Auth", registryAuth) + .accept(MediaType.APPLICATION_JSON); + + builder.post(null, new TypeReference() { + }, resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExec.java new file mode 100644 index 000000000..63d16bda6 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class RemoveContainerCmdExec extends AbstrSyncDockerCmdExec implements + RemoveContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoveContainerCmdExec.class); + + public RemoveContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(RemoveContainerCmd command) { + WebTarget webTarget = getBaseResource().path("/containers/" + command.getContainerId()); + + webTarget = booleanQueryParam(webTarget, "v", command.hasRemoveVolumesEnabled()); + webTarget = booleanQueryParam(webTarget, "force", command.hasForceEnabled()); + + LOGGER.trace("DELETE: {}", webTarget); + webTarget.request().accept(MediaType.APPLICATION_JSON).delete(); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/RemoveImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/RemoveImageCmdExec.java new file mode 100644 index 000000000..35ae053d3 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/RemoveImageCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.RemoveImageCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class RemoveImageCmdExec extends AbstrSyncDockerCmdExec implements RemoveImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoveImageCmdExec.class); + + public RemoveImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(RemoveImageCmd command) { + WebTarget webTarget = getBaseResource().path("/images/" + command.getImageId()); + + webTarget = booleanQueryParam(webTarget, "force", command.hasForceEnabled()); + webTarget = booleanQueryParam(webTarget, "noprune", command.hasNoPruneEnabled()); + + LOGGER.trace("DELETE: {}", webTarget); + webTarget.request().delete(); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/RestartContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/RestartContainerCmdExec.java new file mode 100644 index 000000000..6c1f47a0b --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/RestartContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.RestartContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + + +public class RestartContainerCmdExec extends AbstrSyncDockerCmdExec implements + RestartContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(RestartContainerCmdExec.class); + + public RestartContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(RestartContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/restart").resolveTemplate("id", + command.getContainerId()); + + if (command.getTimeout() != null) { + webResource = webResource.queryParam("t", String.valueOf(command.getTimeout())); + } + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/SaveImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/SaveImageCmdExec.java new file mode 100644 index 000000000..629f49871 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/SaveImageCmdExec.java @@ -0,0 +1,28 @@ +package com.github.dockerjava.netty.exec; + +import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.SaveImageCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class SaveImageCmdExec extends AbstrSyncDockerCmdExec implements SaveImageCmd.Exec { + private static final Logger LOGGER = LoggerFactory.getLogger(SaveImageCmdExec.class); + + public SaveImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected InputStream execute(SaveImageCmd command) { + WebTarget webResource = getBaseResource().path("/images/" + command.getName() + "/get").queryParam("tag", + command.getTag()); + + LOGGER.trace("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON).get(); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/SearchImagesCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/SearchImagesCmdExec.java new file mode 100644 index 000000000..d31d00a9f --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/SearchImagesCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.SearchImagesCmd; +import com.github.dockerjava.api.model.SearchItem; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class SearchImagesCmdExec extends AbstrSyncDockerCmdExec> implements + SearchImagesCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(SearchImagesCmdExec.class); + + public SearchImagesCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected List execute(SearchImagesCmd command) { + WebTarget webResource = getBaseResource().path("/images/search").queryParam("term", command.getTerm()); + + LOGGER.trace("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference>() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/StartContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/StartContainerCmdExec.java new file mode 100644 index 000000000..12f2d8cbc --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/StartContainerCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class StartContainerCmdExec extends AbstrSyncDockerCmdExec implements + StartContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(StartContainerCmdExec.class); + + public StartContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(StartContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/start").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(command); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/StatsCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/StatsCmdExec.java new file mode 100644 index 000000000..d167d5686 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/StatsCmdExec.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.StatsCmd; +import com.github.dockerjava.api.model.Statistics; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class StatsCmdExec extends AbstrAsyncDockerCmdExec implements StatsCmd.Exec { + private static final Logger LOGGER = LoggerFactory.getLogger(StatsCmdExec.class); + + public StatsCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(StatsCmd command, ResultCallback resultCallback) { + + WebTarget webTarget = getBaseResource().path("/containers/{id}/stats").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("GET: {}", webTarget); + + webTarget.request().get(new TypeReference() { + }, resultCallback); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/StopContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/StopContainerCmdExec.java new file mode 100644 index 000000000..3bade97e7 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/StopContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.StopContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + + + +public class StopContainerCmdExec extends AbstrSyncDockerCmdExec implements + StopContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(StopContainerCmdExec.class); + + public StopContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(StopContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/stop").resolveTemplate("id", + command.getContainerId()); + + if (command.getTimeout() != null) { + webResource = webResource.queryParam("t", String.valueOf(command.getTimeout())); + } + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/TagImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/TagImageCmdExec.java new file mode 100644 index 000000000..6aa171f86 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/TagImageCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.TagImageCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.WebTarget; + +public class TagImageCmdExec extends AbstrSyncDockerCmdExec implements TagImageCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(TagImageCmdExec.class); + + public TagImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(TagImageCmd command) { + WebTarget webTarget = getBaseResource().path("/images/" + command.getImageId() + "/tag") + .queryParam("repo", command.getRepository()).queryParam("tag", command.getTag()); + + webTarget = booleanQueryParam(webTarget, "force", command.hasForceEnabled()); + + LOGGER.trace("POST: {}", webTarget); + webTarget.request().post(null); + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/TopContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/TopContainerCmdExec.java new file mode 100644 index 000000000..07ec12b03 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/TopContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.TopContainerCmd; +import com.github.dockerjava.api.command.TopContainerResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class TopContainerCmdExec extends AbstrSyncDockerCmdExec implements + TopContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(TopContainerCmdExec.class); + + public TopContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected TopContainerResponse execute(TopContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/top").resolveTemplate("id", + command.getContainerId()); + + if (!StringUtils.isEmpty(command.getPsArgs())) + webResource = webResource.queryParam("ps_args", command.getPsArgs()); + + LOGGER.trace("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/UnpauseContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/UnpauseContainerCmdExec.java new file mode 100644 index 000000000..c7cbfe017 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/UnpauseContainerCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.api.command.UnpauseContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class UnpauseContainerCmdExec extends AbstrSyncDockerCmdExec implements + UnpauseContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(UnpauseContainerCmdExec.class); + + public UnpauseContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(UnpauseContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/unpause").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: {}", webResource); + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/VersionCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/VersionCmdExec.java new file mode 100644 index 000000000..84857c208 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/VersionCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.VersionCmd; +import com.github.dockerjava.api.model.Version; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class VersionCmdExec extends AbstrSyncDockerCmdExec implements VersionCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(VersionCmdExec.class); + + public VersionCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Version execute(VersionCmd command) { + WebTarget webResource = getBaseResource().path("/version"); + + LOGGER.trace("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference() { + }); + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/exec/WaitContainerCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/WaitContainerCmdExec.java new file mode 100644 index 000000000..5883b7188 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/exec/WaitContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.netty.exec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.WaitContainerCmd; +import com.github.dockerjava.api.model.WaitResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.netty.MediaType; +import com.github.dockerjava.netty.WebTarget; + +public class WaitContainerCmdExec extends AbstrAsyncDockerCmdExec implements + WaitContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(WaitContainerCmdExec.class); + + public WaitContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(WaitContainerCmd command, ResultCallback resultCallback) { + WebTarget webTarget = getBaseResource().path("/containers/{id}/wait").resolveTemplate("id", + command.getContainerId()); + + LOGGER.trace("POST: {}", webTarget); + + webTarget.request().accept(MediaType.APPLICATION_JSON).post((Object) null, new TypeReference() { + }, resultCallback); + + return null; + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandler.java b/src/main/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandler.java new file mode 100644 index 000000000..87878f0da --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandler.java @@ -0,0 +1,149 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.api.model.StreamType; + +/** + * Handler that decodes a docker-raw-stream as described here: + * + * https://docs.docker.com/engine/reference/api/docker_remote_api_v1.21/#attach-to-a-container + * + * It drives the {@link ResultCallback#onNext(Object)} method of the passed {@link ResultCallback}. + * + * @author Marcus Linke + */ +public class FramedResponseStreamHandler extends SimpleChannelInboundHandler { + + private static final int HEADER_SIZE = 8; + + private final ByteBuf rawBuffer = Unpooled.buffer(1000); + + private byte[] header = new byte[HEADER_SIZE]; + + private int headerCnt = 0; + + private byte[] payload = new byte[0]; + + private int payloadCnt = 0; + + private ResultCallback resultCallback; + + private StreamType streamType = null; + + public FramedResponseStreamHandler(ResultCallback resultCallback) { + this.resultCallback = resultCallback; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { + + rawBuffer.writeBytes(msg.copy(), 0, msg.readableBytes()); + + Frame frame = null; + + do { + frame = decode(); + + if (frame != null) { + resultCallback.onNext(frame); + } + + } while (frame != null); + } + + private int read(byte[] buf, int offset, int length) { + length = Math.min(rawBuffer.readableBytes(), length); + rawBuffer.readBytes(buf, offset, length); + return length; + } + + private Frame decode() { + if (headerCnt < HEADER_SIZE) { + + int headerCount = read(header, headerCnt, HEADER_SIZE - headerCnt); + + if (headerCount == 0) { + return null; + } + + headerCnt += headerCount; + + if (headerCnt < HEADER_SIZE) { + return null; + } + + streamType = streamType(header[0]); + + if (streamType.equals(StreamType.RAW)) { + return new Frame(streamType, header); + } + } + + if (streamType.equals(StreamType.RAW)) { + + if (payloadCnt == 0) + payload = new byte[rawBuffer.readableBytes()]; + + int count = read(payload, payloadCnt, rawBuffer.readableBytes()); + + if (count == 0) { + return null; + } + + payloadCnt = 0; + + return new Frame(StreamType.RAW, payload); + } else { + + int payloadSize = ((header[4] & 0xff) << 24) + ((header[5] & 0xff) << 16) + ((header[6] & 0xff) << 8) + + (header[7] & 0xff); + + if (payloadCnt == 0) { + payload = new byte[payloadSize]; + } + + int count = read(payload, payloadCnt, payloadSize - payloadCnt); + + if (count == 0) { + return null; + } + + payloadCnt += count; + + if (payloadCnt < payloadSize) { + return null; + } + + headerCnt = 0; + payloadCnt = 0; + + return new Frame(streamType, payload); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + resultCallback.onError(cause); + ctx.close(); + } + + private static StreamType streamType(byte streamType) { + switch (streamType) { + case 0: + return StreamType.STDIN; + case 1: + return StreamType.STDOUT; + case 2: + return StreamType.STDERR; + default: + return StreamType.RAW; + } + } + +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/HttpConnectionHijackHandler.java b/src/main/java/com/github/dockerjava/netty/handler/HttpConnectionHijackHandler.java new file mode 100644 index 000000000..3010682f6 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/HttpConnectionHijackHandler.java @@ -0,0 +1,46 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpClientUpgradeHandler; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; + +public class HttpConnectionHijackHandler implements HttpClientUpgradeHandler.UpgradeCodec { + + private CountDownLatch latch = new CountDownLatch(1); + + private HttpResponseHandler httpResponseHandler; + + public HttpConnectionHijackHandler(HttpResponseHandler httpResponseHandler) { + this.httpResponseHandler = httpResponseHandler; + } + + @Override + public void upgradeTo(ChannelHandlerContext ctx, FullHttpResponse upgradeResponse) throws Exception { + httpResponseHandler.channelRead(ctx, upgradeResponse); + ctx.pipeline().addLast(httpResponseHandler); + latch.countDown(); + } + + @Override + public Collection setUpgradeHeaders(ChannelHandlerContext ctx, HttpRequest upgradeRequest) { + return Collections.emptyList(); + } + + @Override + public CharSequence protocol() { + return "tcp"; + } + + public void awaitUpgrade() { + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/HttpRequestProvider.java b/src/main/java/com/github/dockerjava/netty/handler/HttpRequestProvider.java new file mode 100644 index 000000000..0d861cc01 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/HttpRequestProvider.java @@ -0,0 +1,8 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.handler.codec.http.HttpRequest; + +public interface HttpRequestProvider { + + public HttpRequest getHttpRequest(String uri); +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/HttpResponseHandler.java b/src/main/java/com/github/dockerjava/netty/handler/HttpResponseHandler.java new file mode 100644 index 000000000..2f11ccf38 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/HttpResponseHandler.java @@ -0,0 +1,116 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpObject; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; + +import java.nio.charset.Charset; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.exception.BadRequestException; +import com.github.dockerjava.api.exception.ConflictException; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.InternalServerErrorException; +import com.github.dockerjava.api.exception.NotAcceptableException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.exception.NotModifiedException; +import com.github.dockerjava.api.exception.UnauthorizedException; + +/** + * Handler that is responsible to handle an incoming {@link HttpResponse}. It evaluates the status code and + * triggers the appropriate lifecycle methods at the passed {@link ResultCallback}. + * + * @author Marcus Linke + */ +public class HttpResponseHandler extends SimpleChannelInboundHandler { + + private HttpResponse response; + + private ByteBuf errorBody = Unpooled.buffer(); + + private HttpRequestProvider requestProvider; + + private ResultCallback resultCallback; + + public HttpResponseHandler(HttpRequestProvider requestProvider, ResultCallback resultCallback) { + super(false); + this.requestProvider = requestProvider; + this.resultCallback = resultCallback; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { + if (msg instanceof HttpResponse) { + + response = (HttpResponse) msg; + } else if (msg instanceof HttpContent) { + + HttpContent content = (HttpContent) msg; + + ByteBuf byteBuf = content.content(); + + switch (response.status().code()) { + case 200: + case 201: + case 204: + ctx.fireChannelRead(byteBuf); + break; + default: + errorBody.writeBytes(byteBuf); + } + + if (content instanceof LastHttpContent) { + try { + + switch (response.status().code()) { + case 101: + case 200: + case 201: + case 204: + break; + case 301: + case 302: + if (response.headers().contains(HttpHeaderNames.LOCATION)) { + String location = response.headers().get(HttpHeaderNames.LOCATION); + HttpRequest redirected = requestProvider.getHttpRequest(location); + + ctx.channel().writeAndFlush(redirected); + } + break; + case 304: + throw new NotModifiedException(getBodyAsMessage(errorBody)); + case 400: + throw new BadRequestException(getBodyAsMessage(errorBody)); + case 401: + throw new UnauthorizedException(getBodyAsMessage(errorBody)); + case 404: + throw new NotFoundException(getBodyAsMessage(errorBody)); + case 406: + throw new NotAcceptableException(getBodyAsMessage(errorBody)); + case 409: + throw new ConflictException(getBodyAsMessage(errorBody)); + case 500: + throw new InternalServerErrorException(getBodyAsMessage(errorBody)); + default: + throw new DockerException(getBodyAsMessage(errorBody), response.status().code()); + } + } catch (Throwable e) { + resultCallback.onError(e); + } finally { + resultCallback.onComplete(); + } + } + } + } + + private String getBodyAsMessage(ByteBuf body) { + return body.readBytes(body.readableBytes()).toString(Charset.forName("UTF-8")); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandler.java b/src/main/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandler.java new file mode 100644 index 000000000..b3800be56 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandler.java @@ -0,0 +1,100 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.github.dockerjava.api.async.ResultCallback; + +/** + * Handler that converts an incoming byte stream to an {@link InputStream}. + * + * @author marcus + */ +public class HttpResponseStreamHandler extends SimpleChannelInboundHandler { + + private HttpResponseInputStream stream = new HttpResponseInputStream(); + + public HttpResponseStreamHandler(ResultCallback resultCallback) { + resultCallback.onNext(stream); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { + stream.write(msg.copy()); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + stream.close(); + super.channelReadComplete(ctx); + } + + public static class HttpResponseInputStream extends InputStream { + + private AtomicBoolean closed = new AtomicBoolean(false); + + private LinkedTransferQueue queue = new LinkedTransferQueue(); + + private ByteBuf current = null; + + public void write(ByteBuf byteBuf) { + queue.put(byteBuf); + } + + @Override + public void close() throws IOException { + closed.set(true); + super.close(); + } + + @Override + public int available() throws IOException { + poll(); + return readableBytes(); + } + + private int readableBytes() { + if (current != null) { + return current.readableBytes(); + } else { + return 0; + } + + } + + @Override + public int read() throws IOException { + + poll(); + + if (readableBytes() == 0) { + if (closed.get()) { + return -1; + } + } + + if (current != null && current.readableBytes() > 0) { + return current.readByte(); + } else { + return read(); + } + } + + private void poll() { + if (readableBytes() == 0) { + try { + current = queue.poll(50, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java b/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java new file mode 100644 index 000000000..54ffb2f96 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java @@ -0,0 +1,23 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Handler that encodes an outgoing object to JSON. + * + * @author Marcus Linke + */ +public class JsonRequestHandler extends MessageToByteEncoder{ + + private ObjectMapper mapper = new ObjectMapper(); + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + byte[] serialized = mapper.writeValueAsBytes(msg); + out.writeBytes(serialized); + } +} diff --git a/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java b/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java new file mode 100644 index 000000000..b5f76ab73 --- /dev/null +++ b/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java @@ -0,0 +1,51 @@ +package com.github.dockerjava.netty.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.async.ResultCallback; + +/** + * Handler that decodes an incoming byte stream into objects of T and calls {@link ResultCallback#onNext(Object)} + * + * @author Marcus Linke + */ +public class JsonResponseCallbackHandler extends SimpleChannelInboundHandler { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + private TypeReference typeReference; + + private ResultCallback callback; + + public JsonResponseCallbackHandler(TypeReference typeReference, ResultCallback callback) { + this.typeReference = typeReference; + this.callback = callback; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { + byte[] buffer = new byte[msg.readableBytes()]; + msg.readBytes(buffer); + + T object = null; + + try { + object = objectMapper.readValue(buffer, typeReference); + } catch (Exception e) { + callback.onError(e); + throw new RuntimeException(e); + } + + callback.onNext(object); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + callback.onError(cause); + ctx.close(); + } +} diff --git a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java index eff85b852..cdf7f457e 100644 --- a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java +++ b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java @@ -1,8 +1,5 @@ package com.github.dockerjava.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -28,7 +25,6 @@ import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.Volume; -import com.github.dockerjava.api.model.VolumeBind; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.TestDockerCmdExecFactory; @@ -44,8 +40,12 @@ public abstract class AbstractDockerClientTest extends Assert { protected DockerClient dockerClient; - protected TestDockerCmdExecFactory dockerCmdExecFactory = new TestDockerCmdExecFactory( - DockerClientBuilder.getDefaultDockerCmdExecFactory()); + protected TestDockerCmdExecFactory dockerCmdExecFactory = initTestDockerCmdExecFactory(); + + protected TestDockerCmdExecFactory initTestDockerCmdExecFactory() { + return new TestDockerCmdExecFactory( + DockerClientBuilder.getDefaultDockerCmdExecFactory()); + } public void beforeTest() throws Exception { @@ -53,10 +53,13 @@ public void beforeTest() throws Exception { LOG.info("Connecting to Docker server"); dockerClient = DockerClientBuilder.getInstance(config()).withDockerCmdExecFactory(dockerCmdExecFactory).build(); - LOG.info("Pulling image 'busybox'"); - - // need to block until image is pulled completely - dockerClient.pullImageCmd("busybox").withTag("latest").exec(new PullImageResultCallback()).awaitSuccess(); + try { + dockerClient.inspectImageCmd("busybox").exec(); + } catch (Exception e) { + LOG.info("Pulling image 'busybox'"); + // need to block until image is pulled completely + dockerClient.pullImageCmd("busybox").withTag("latest").exec(new PullImageResultCallback()).awaitSuccess(); + } assertNotNull(dockerClient); LOG.info("======================= END OF BEFORETEST =======================\n\n"); @@ -204,7 +207,8 @@ public static class LogContainerTestCallback extends LogContainerResultCallback @Override public void onNext(Frame frame) { log.append(new String(frame.getPayload())); - super.onNext(frame); + System.err.println("LogContainerTestCallback: " + log.toString()); + //super.onNext(frame); } @Override diff --git a/src/test/java/com/github/dockerjava/core/NameParserTest.java b/src/test/java/com/github/dockerjava/core/NameParserTest.java index afae80ebb..865f9a401 100644 --- a/src/test/java/com/github/dockerjava/core/NameParserTest.java +++ b/src/test/java/com/github/dockerjava/core/NameParserTest.java @@ -16,7 +16,7 @@ /** * * - * @author marcus + * @author Marcus Linke * */ public class NameParserTest { diff --git a/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java b/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java index d1ff920b0..4a96e664f 100644 --- a/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java +++ b/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java @@ -53,7 +53,7 @@ * Special {@link DockerCmdExecFactory} implementation that collects container and image creations while test execution * for the purpose of automatically cleanup. * - * @author marcus + * @author Marcus Linke */ public class TestDockerCmdExecFactory implements DockerCmdExecFactory { diff --git a/src/test/java/com/github/dockerjava/core/command/AttachContainerCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/AttachContainerCmdImplTest.java index ead8ad39e..be2d5fdd0 100644 --- a/src/test/java/com/github/dockerjava/core/command/AttachContainerCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/AttachContainerCmdImplTest.java @@ -5,7 +5,9 @@ import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; +import java.io.ByteArrayInputStream; import java.io.File; +import java.io.InputStream; import java.lang.reflect.Method; import java.util.concurrent.TimeUnit; @@ -104,6 +106,33 @@ public void onNext(Frame frame) { assertThat(callback.toString(), containsString("stdout\r\nstderr")); } + @Test(expectedExceptions = UnsupportedOperationException.class) + public void attachContainerStdinUnsupported() throws Exception { + + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("echo", snippet) + .withTty(false).exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + AttachContainerTestCallback callback = new AttachContainerTestCallback() { + @Override + public void onNext(Frame frame) { + assertEquals(frame.getStreamType(), StreamType.STDOUT); + super.onNext(frame); + }; + }; + + InputStream stdin = new ByteArrayInputStream("".getBytes()); + + dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true) + .withLogs(true).withStdIn(stdin).exec(callback).awaitCompletion(30, TimeUnit.SECONDS).close(); + } + public static class AttachContainerTestCallback extends AttachContainerResultCallback { private StringBuffer log = new StringBuffer(); 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 5144f2d4f..6d15cf03b 100644 --- a/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java @@ -54,7 +54,8 @@ public void execStart() throws Exception { ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()) .withAttachStdout(true).withCmd("touch", "/execStartTest.log").exec(); - dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec( + new ExecStartResultCallback(System.out, System.err)); InputStream response = dockerClient.copyArchiveFromContainerCmd(container.getId(), "/execStartTest.log").exec(); Boolean bytesAvailable = response.available() > 0; @@ -79,7 +80,8 @@ public void execStartAttached() throws Exception { ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()) .withAttachStdout(true).withCmd("touch", "/execStartTest.log").exec(); - dockerClient.execStartCmd(execCreateCmdResponse.getId()).withDetach(false).withTty(true).exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).withDetach(false).withTty(true) + .exec(new ExecStartResultCallback(System.out, System.err)); InputStream response = dockerClient.copyArchiveFromContainerCmd(container.getId(), "/execStartTest.log").exec(); Boolean bytesAvailable = response.available() > 0; diff --git a/src/test/java/com/github/dockerjava/core/command/InspectExecCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/InspectExecCmdImplTest.java index 744bbe82c..4f88b6317 100644 --- a/src/test/java/com/github/dockerjava/core/command/InspectExecCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/InspectExecCmdImplTest.java @@ -67,25 +67,23 @@ public void inspectExecTest() throws IOException { assertThat(checkFileCmdCreateResponse.getId(), not(isEmptyString())); // Check that file does not exist - InputStream response1 = dockerClient.execStartCmd(container.getId()) - .withExecId(checkFileCmdCreateResponse.getId()).exec(); - asString(response1); // consume + dockerClient.execStartCmd(container.getId()) + .withExecId(checkFileCmdCreateResponse.getId()).exec(new ExecStartResultCallback(System.out, System.err)); + InspectExecResponse first = dockerClient.inspectExecCmd(checkFileCmdCreateResponse.getId()).exec(); assertThat(first.getExitCode(), is(1)); // Create the file - InputStream response2 = dockerClient.execStartCmd(container.getId()) - .withExecId(touchFileCmdCreateResponse.getId()).exec(); - asString(response2); + dockerClient.execStartCmd(container.getId()) + .withExecId(touchFileCmdCreateResponse.getId()).exec(new ExecStartResultCallback(System.out, System.err)); InspectExecResponse second = dockerClient.inspectExecCmd(touchFileCmdCreateResponse.getId()).exec(); assertThat(second.getExitCode(), is(0)); // Check that file does exist now - InputStream response3 = dockerClient.execStartCmd(container.getId()) - .withExecId(checkFileCmdCreateResponse.getId()).exec(); - asString(response3); + dockerClient.execStartCmd(container.getId()) + .withExecId(checkFileCmdCreateResponse.getId()).exec(new ExecStartResultCallback(System.out, System.err)); InspectExecResponse third = dockerClient.inspectExecCmd(checkFileCmdCreateResponse.getId()).exec(); assertThat(third.getExitCode(), is(0)); diff --git a/src/test/java/com/github/dockerjava/netty/AbstractNettyDockerClientTest.java b/src/test/java/com/github/dockerjava/netty/AbstractNettyDockerClientTest.java new file mode 100644 index 000000000..6dcb435f1 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/AbstractNettyDockerClientTest.java @@ -0,0 +1,18 @@ +package com.github.dockerjava.netty; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.dockerjava.client.AbstractDockerClientTest; +import com.github.dockerjava.core.TestDockerCmdExecFactory; + +public abstract class AbstractNettyDockerClientTest extends AbstractDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(AbstractNettyDockerClientTest.class); + + @Override + protected TestDockerCmdExecFactory initTestDockerCmdExecFactory() { + return new TestDockerCmdExecFactory( + new DockerCmdExecFactoryImpl()); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/AttachContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/AttachContainerCmdExecTest.java new file mode 100644 index 000000000..fe34aa537 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/AttachContainerCmdExecTest.java @@ -0,0 +1,157 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.api.model.StreamType; +import com.github.dockerjava.core.command.AttachContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class AttachContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void attachContainerWithoutTTY() throws Exception { + + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("echo", snippet) + .withTty(false).exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + AttachContainerTestCallback callback = new AttachContainerTestCallback() { + @Override + public void onNext(Frame frame) { + assertEquals(frame.getStreamType(), StreamType.STDOUT); + super.onNext(frame); + }; + }; + + dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true) + .withLogs(true).exec(callback).awaitCompletion(10, TimeUnit.SECONDS).close(); + + assertThat(callback.toString(), containsString(snippet)); + } + + @Test + public void attachContainerWithStdin() throws Exception { + + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("/bin/sh", "-c", "read line && echo $line") + .withTty(false).withStdinOpen(true).exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertTrue(inspectContainerResponse.getState().getRunning()); + + AttachContainerTestCallback callback = new AttachContainerTestCallback() { + + @Override + public void onNext(Frame frame) { + assertEquals(frame.getStreamType(), StreamType.STDOUT); + super.onNext(frame); + }; + }; + + InputStream stdin = new ByteArrayInputStream((snippet + "\n").getBytes()); + + dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true) + .withStdIn(stdin).exec(callback).awaitCompletion(2, TimeUnit.SECONDS).close(); + + assertThat(callback.toString(), containsString(snippet)); + } + + @Test + public void attachContainerWithTTY() throws Exception { + + File baseDir = new File(Thread.currentThread().getContextClassLoader() + .getResource("attachContainerTestDockerfile").getFile()); + + String imageId = buildImage(baseDir); + + CreateContainerResponse container = dockerClient.createContainerCmd(imageId).withTty(true).exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + AttachContainerTestCallback callback = new AttachContainerTestCallback() { + @Override + public void onNext(Frame frame) { + assertEquals(frame.getStreamType(), StreamType.RAW); + super.onNext(frame); + }; + }; + + dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true) + .exec(callback).awaitCompletion(10, TimeUnit.SECONDS).close(); + + // HexDump.dump(collectFramesCallback.toString().getBytes(), 0, System.out, 0); + + assertThat(callback.toString(), containsString("stdout\r\nstderr")); + } + + public static class AttachContainerTestCallback extends AttachContainerResultCallback { + private StringBuffer log = new StringBuffer(); + + @Override + public void onNext(Frame item) { + log.append(new String(item.getPayload())); + super.onNext(item); + } + + @Override + public String toString() { + return log.toString(); + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/AuthCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/AuthCmdExecTest.java new file mode 100644 index 000000000..66ac1bce3 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/AuthCmdExecTest.java @@ -0,0 +1,57 @@ +package com.github.dockerjava.netty.exec; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.exception.UnauthorizedException; +import com.github.dockerjava.api.model.AuthResponse; +import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class AuthCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void testAuth() throws Exception { + AuthResponse response = dockerClient.authCmd().exec(); + + assertEquals(response.getStatus(), "Login Succeeded"); + } + + @Test() + public void testAuthInvalid() throws Exception { + + try { + DockerClientBuilder.getInstance(config("garbage")).build().authCmd().exec(); + fail("Expected a UnauthorizedException caused by a bad password."); + } catch (UnauthorizedException e) { + assertEquals(e.getMessage(), "Wrong login/password, please try again\n"); + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java new file mode 100644 index 000000000..19b42420e --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java @@ -0,0 +1,296 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.UUID; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.TrueFileFilter; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.core.command.BuildImageResultCallback; +import com.github.dockerjava.core.command.PushImageResultCallback; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.core.util.CompressArchiveUtil; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class BuildImageCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void testNginxDockerfileBuilder() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("nginx").getFile()); + + String imageId = buildImage(baseDir); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + assertThat(inspectImageResponse.getAuthor(), equalTo("Guillaume J. Charmes \"guillaume@dotcloud.com\"")); + } + + @Test(groups = "ignoreInCircleCi") + public void testNonstandard1() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader() + .getResource("nonstandard/subdirectory/Dockerfile-nonstandard").getFile()); + + buildImage(baseDir); + } + + @Test(groups = "ignoreInCircleCi") + public void testNonstandard2() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("nonstandard").getFile()); + File dockerFile = new File(Thread.currentThread().getContextClassLoader() + .getResource("nonstandard/subdirectory/Dockerfile-nonstandard").getFile()); + + dockerClient.buildImageCmd().withBaseDirectory(baseDir).withDockerfile(dockerFile).withNoCache(true) + .exec(new BuildImageResultCallback()).awaitImageId(); + } + + @Test + public void testDockerBuilderFromTar() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFile").getFile()); + Collection files = FileUtils.listFiles(baseDir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE); + File tarFile = CompressArchiveUtil.archiveTARFiles(baseDir, files, UUID.randomUUID().toString()); + String response = dockerfileBuild(new FileInputStream(tarFile)); + assertThat(response, containsString("Successfully executed testrun.sh")); + } + + @Test + public void testDockerBuilderAddUrl() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddUrl").getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("Docker")); + } + + @Test + public void testDockerBuilderAddFileInSubfolder() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFileInSubfolder") + .getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("Successfully executed testrun.sh")); + } + + @Test + public void testDockerBuilderAddFilesViaWildcard() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFilesViaWildcard") + .getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("Successfully executed testinclude1.sh")); + assertThat(response, not(containsString("Successfully executed testinclude2.sh"))); + } + + @Test + public void testDockerBuilderAddFolder() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFolder").getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("Successfully executed testAddFolder.sh")); + } + + @Test + public void testDockerBuilderEnv() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testEnv").getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("Successfully executed testrun.sh")); + } + + private String dockerfileBuild(InputStream tarInputStream) throws Exception { + + return execBuild(dockerClient.buildImageCmd().withTarInputStream(tarInputStream)); + } + + private String dockerfileBuild(File baseDir) throws Exception { + + return execBuild(dockerClient.buildImageCmd(baseDir)); + } + + private String execBuild(BuildImageCmd buildImageCmd) throws Exception { + String imageId = buildImageCmd.withNoCache(true).exec(new BuildImageResultCallback()).awaitImageId(); + + // Create container based on image + CreateContainerResponse container = dockerClient.createContainerCmd(imageId).exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode(); + + return containerLog(container.getId()); + } + + @Test(expectedExceptions = { DockerClientException.class }) + public void testDockerfileIgnored() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testDockerfileIgnored") + .getFile()); + + dockerClient.buildImageCmd(baseDir).withNoCache(true).exec(new BuildImageResultCallback()).awaitImageId(); + } + + @Test + public void testDockerfileNotIgnored() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testDockerfileNotIgnored") + .getFile()); + + dockerClient.buildImageCmd(baseDir).withNoCache(true).exec(new BuildImageResultCallback()).awaitImageId(); + } + + @Test(expectedExceptions = { DockerClientException.class }) + public void testInvalidDockerIgnorePattern() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader() + .getResource("testInvalidDockerignorePattern").getFile()); + + dockerClient.buildImageCmd(baseDir).withNoCache(true).exec(new BuildImageResultCallback()).awaitImageId(); + } + + @Test(groups = "ignoreInCircleCi") + public void testDockerIgnore() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testDockerignore") + .getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("/tmp/a/a /tmp/a/c /tmp/a/d")); + } + + @Test + public void testNetCatDockerfileBuilder() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("netcat").getFile()); + + String imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true).exec(new BuildImageResultCallback()) + .awaitImageId(); + + assertNotNull(imageId, "Not successful in build"); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + assertThat(inspectImageResponse.getId(), not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + CreateContainerResponse container = dockerClient.createContainerCmd(inspectImageResponse.getId()).exec(); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getId(), notNullValue()); + assertThat(inspectContainerResponse.getNetworkSettings().getPorts(), notNullValue()); + + // No use as such if not running on the server + // for (Ports.Port p : inspectContainerResponse.getNetworkSettings().getPorts().getAllPorts()) { + // int port = Integer.valueOf(p.getHostPort()); + // LOG.info("Checking port {} is open", port); + // assertThat(available(port), is(false)); + // } + dockerClient.stopContainerCmd(container.getId()).withTimeout(0).exec(); + + } + + @Test + public void testAddAndCopySubstitution() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testENVSubstitution") + .getFile()); + String response = dockerfileBuild(baseDir); + assertThat(response, containsString("testENVSubstitution successfully completed")); + } + + @Test + public void testBuildFromPrivateRegistry() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("privateRegistry").getFile()); + + String imageId = buildImage(baseDir); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + dockerClient.tagImageCmd(imageId, "testregistry", "2").withForce().exec(); + + // see https://github.com/docker/distribution/blob/master/docs/deploying.md#native-basic-auth + CreateContainerResponse testregistry = dockerClient + .createContainerCmd("testregistry:2") + .withName("registry") + .withPortBindings(new PortBinding(new Ports.Binding(5000), ExposedPort.tcp(5000))) + .withEnv("REGISTRY_AUTH=htpasswd", "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", + "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", "REGISTRY_LOG_LEVEL=debug", + "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key") + .exec(); + + dockerClient.startContainerCmd(testregistry.getId()).exec(); + + AuthConfig authConfig = new AuthConfig(); + + // credentials as configured in /auth/htpasswd + authConfig.setUsername("testuser"); + authConfig.setPassword("testpassword"); + authConfig.setEmail("foo@bar.de"); + authConfig.setServerAddress("localhost:5000"); + + dockerClient.authCmd().withAuthConfig(authConfig).exec(); + dockerClient.tagImageCmd("busybox:latest", "localhost:5000/testuser/busybox", "latest").withForce().exec(); + + dockerClient.pushImageCmd("localhost:5000/testuser/busybox").withTag("latest").withAuthConfig(authConfig) + .exec(new PushImageResultCallback()).awaitSuccess(); + + dockerClient.removeImageCmd("localhost:5000/testuser/busybox").withForce(true).exec(); + + baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testBuildFromPrivateRegistry") + .getFile()); + + AuthConfigurations authConfigurations = new AuthConfigurations(); + authConfigurations.addConfig(authConfig); + + imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true).withBuildAuthConfigs(authConfigurations) + .exec(new BuildImageResultCallback()).awaitImageId(); + + inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/CommitCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/CommitCmdExecTest.java new file mode 100644 index 000000000..0186f4233 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/CommitCmdExecTest.java @@ -0,0 +1,80 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class CommitCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void commit() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("touch", "/test").exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + LOG.info("Commiting container: {}", container.toString()); + String imageId = dockerClient.commitCmd(container.getId()).exec(); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + assertThat(inspectImageResponse, hasField("container", startsWith(container.getId()))); + assertThat(inspectImageResponse.getContainerConfig().getImage(), equalTo("busybox")); + + InspectImageResponse busyboxImg = dockerClient.inspectImageCmd("busybox").exec(); + + assertThat(inspectImageResponse.getParent(), equalTo(busyboxImg.getId())); + } + + @Test + public void commitNonExistingContainer() throws DockerException { + try { + dockerClient.commitCmd("non-existent").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExecTest.java new file mode 100644 index 000000000..57c4b46a0 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/ContainerDiffCmdExecTest.java @@ -0,0 +1,80 @@ +package com.github.dockerjava.netty.exec; + +import static ch.lambdaj.Lambda.selectUnique; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; +import java.util.List; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.ChangeLog; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class ContainerDiffCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void testContainerDiff() throws DockerException { + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("touch", "/test").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()) + .awaitStatusCode(); + assertThat(exitCode, equalTo(0)); + + List filesystemDiff = dockerClient.containerDiffCmd(container.getId()).exec(); + LOG.info("Container DIFF: {}", filesystemDiff.toString()); + + assertThat(filesystemDiff.size(), equalTo(1)); + ChangeLog testChangeLog = selectUnique(filesystemDiff, hasField("path", equalTo("/test"))); + + assertThat(testChangeLog, hasField("path", equalTo("/test"))); + assertThat(testChangeLog, hasField("kind", equalTo(1))); + } + + @Test + public void testContainerDiffWithNonExistingContainer() throws DockerException { + try { + dockerClient.containerDiffCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExecTest.java new file mode 100644 index 000000000..aa4dcc575 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveFromContainerCmdExecTest.java @@ -0,0 +1,73 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; + +import java.io.InputStream; +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class CopyArchiveFromContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void copyFromContainer() throws Exception { + // TODO extract this into a shared method + CreateContainerResponse container = dockerClient.createContainerCmd("busybox") + .withName("docker-java-itest-copyFromContainer").withCmd("touch", "/copyFromContainer").exec(); + + LOG.info("Created container: {}", container); + assertThat(container.getId(), not(isEmptyOrNullString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InputStream response = dockerClient.copyArchiveFromContainerCmd(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.copyArchiveFromContainerCmd("non-existing", "/test").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException ignored) { + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExecTest.java new file mode 100644 index 000000000..d755dfcba --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/CopyArchiveToContainerCmdExecTest.java @@ -0,0 +1,94 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.core.util.CompressArchiveUtil; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class CopyArchiveToContainerCmdExecTest extends AbstractNettyDockerClientTest { + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void copyFileToContainer() throws Exception { + CreateContainerResponse container = prepareContainerForCopy(); + Path temp = Files.createTempFile("", ".tar.gz"); + CompressArchiveUtil.tar(Paths.get("src/test/resources/testReadFile"), temp, true, false); + try (InputStream uploadStream = Files.newInputStream(temp)) { + dockerClient.copyArchiveToContainerCmd(container.getId()).withTarInputStream(uploadStream).exec(); + assertFileCopied(container); + } + } + + @Test + public void copyStreamToContainer() throws Exception { + CreateContainerResponse container = prepareContainerForCopy(); + dockerClient.copyArchiveToContainerCmd(container.getId()).withHostResource("src/test/resources/testReadFile") + .exec(); + assertFileCopied(container); + } + + private CreateContainerResponse prepareContainerForCopy() { + CreateContainerResponse container = dockerClient.createContainerCmd("busybox") + .withName("docker-java-itest-copyToContainer").exec(); + LOG.info("Created container: {}", container); + assertThat(container.getId(), not(isEmptyOrNullString())); + dockerClient.startContainerCmd(container.getId()).exec(); + // Copy a folder to the container + return container; + } + + private void assertFileCopied(CreateContainerResponse container) throws IOException { + try (InputStream response = dockerClient.copyArchiveFromContainerCmd(container.getId(), "testReadFile").exec()) { + boolean bytesAvailable = response.available() > 0; + assertTrue(bytesAvailable, "The file was not copied to the container."); + } + } + + @Test + public void copyToNonExistingContainer() throws Exception { + try { + dockerClient.copyArchiveToContainerCmd("non-existing").withHostResource("src/test/resources/testReadFile") + .exec(); + fail("expected NotFoundException"); + } catch (NotFoundException ignored) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExecTest.java new file mode 100644 index 000000000..b9682c592 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/CopyFileFromContainerCmdExecTest.java @@ -0,0 +1,73 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; + +import java.io.InputStream; +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class CopyFileFromContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void copyFromContainer() throws Exception { + // TODO extract this into a shared method + CreateContainerResponse container = dockerClient.createContainerCmd("busybox") + .withName("docker-java-itest-copyFromContainer").withCmd("touch", "/copyFromContainer").exec(); + + LOG.info("Created container: {}", container); + assertThat(container.getId(), not(isEmptyOrNullString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + 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 ignored) { + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/CreateContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/CreateContainerCmdExecTest.java new file mode 100644 index 000000000..0a11c8ce4 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/CreateContainerCmdExecTest.java @@ -0,0 +1,558 @@ +package com.github.dockerjava.netty.exec; + +import static com.github.dockerjava.api.model.Capability.MKNOD; +import static com.github.dockerjava.api.model.Capability.NET_ADMIN; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItemInArray; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; + +import java.lang.reflect.Method; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.ConflictException; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.AccessMode; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Device; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.Link; +import com.github.dockerjava.api.model.LogConfig; +import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.RestartPolicy; +import com.github.dockerjava.api.model.Ulimit; +import com.github.dockerjava.api.model.Volume; +import com.github.dockerjava.api.model.VolumeRW; +import com.github.dockerjava.api.model.VolumesFrom; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class CreateContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void createContainerWithExistingName() throws DockerException { + + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("env") + .withName(containerName).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + try { + dockerClient.createContainerCmd("busybox").withCmd("env").withName(containerName).exec(); + fail("expected ConflictException"); + } catch (ConflictException e) { + } + } + + @Test + public void createContainerWithVolume() throws DockerException { + + Volume volume = new Volume("/var/log"); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withVolumes(volume) + .withCmd("true").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + LOG.info("Inspect container {}", inspectContainerResponse.getConfig().getVolumes()); + + assertThat(inspectContainerResponse.getConfig().getVolumes().keySet(), contains("/var/log")); + + assertThat(inspectContainerResponse.getMounts().get(0).getDestination(), equalTo(volume)); + assertThat(inspectContainerResponse.getMounts().get(0).getMode(), equalTo("")); + assertThat(inspectContainerResponse.getMounts().get(0).getRW(), equalTo(true)); + } + + @Test + public void createContainerWithReadOnlyVolume() throws DockerException { + + Volume volume = new Volume("/srv/test"); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withVolumes(volume) + .withCmd("true").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + LOG.info("Inspect container {}", inspectContainerResponse.getConfig().getVolumes()); + + assertThat(inspectContainerResponse.getConfig().getVolumes().keySet(), contains("/srv/test")); + + assertThat(inspectContainerResponse.getMounts().get(0).getDestination(), equalTo(volume)); + // TODO: Create a read-only volume and test like this + // assertFalse(inspectContainerResponse.getMounts().get(0).getRW()); + } + + @Test + public void createContainerWithVolumesFrom() throws DockerException { + + Volume volume1 = new Volume("/opt/webapp1"); + Volume volume2 = new Volume("/opt/webapp2"); + + String container1Name = UUID.randomUUID().toString(); + + // create a running container with bind mounts + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName(container1Name) + .withBinds(new Bind("/src/webapp1", volume1), new Bind("/src/webapp2", volume2)).exec(); + LOG.info("Created container1 {}", container1.toString()); + + dockerClient.startContainerCmd(container1.getId()).exec(); + LOG.info("Started container1 {}", container1.toString()); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + + assertThat(inspectContainerResponse1, mountedVolumes(containsInAnyOrder(volume1, volume2))); + + // create a second container with volumes from first container + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withVolumesFrom(new VolumesFrom(container1Name)).exec(); + LOG.info("Created container2 {}", container2.toString()); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + + // No volumes are created, the information is just stored in .HostConfig.VolumesFrom + assertThat(inspectContainerResponse2.getHostConfig().getVolumesFrom(), hasItemInArray(new VolumesFrom( + container1Name))); + + // To ensure that the information stored in VolumesFrom really is considered + // when starting the container, we start it and verify that it has the same + // bind mounts as the first container. + // This is somehow out of scope here, but it helped me to understand how the + // VolumesFrom feature really works. + dockerClient.startContainerCmd(container2.getId()).exec(); + LOG.info("Started container2 {}", container2.toString()); + + inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()).exec(); + + assertThat(inspectContainerResponse2.getHostConfig().getVolumesFrom(), hasItemInArray(new VolumesFrom( + container1Name))); + + assertThat(inspectContainerResponse2, mountedVolumes(containsInAnyOrder(volume1, volume2))); + } + + @Test + public void createContainerWithEnv() throws Exception { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withEnv("VARIABLE=success") + .withCmd("env").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getConfig().getEnv()), containsInAnyOrder("VARIABLE=success")); + + dockerClient.startContainerCmd(container.getId()).exec(); + + assertThat(containerLog(container.getId()), containsString("VARIABLE=success")); + } + + @Test + public void createContainerWithHostname() throws Exception { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withHostName("docker-java") + .withCmd("env").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getConfig().getHostName(), equalTo("docker-java")); + + dockerClient.startContainerCmd(container.getId()).exec(); + + assertThat(containerLog(container.getId()), containsString("HOSTNAME=docker-java")); + } + + @Test + public void createContainerWithName() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withName("container") + .withCmd("env").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getName(), equalTo("/container")); + } + + @Test + public void createContainerWithLink() throws DockerException { + + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container1").exec(); + LOG.info("Created container1 {}", container1.toString()); + assertThat(container1.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + LOG.info("Container1 Inspect: {}", inspectContainerResponse1.toString()); + assertThat(inspectContainerResponse1.getState().getRunning(), is(true)); + + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withName("container2") + .withCmd("env").withLinks(new Link("container1", "container1Link")).exec(); + LOG.info("Created container {}", container2.toString()); + assertThat(container2.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), equalTo(new Link[] { new Link("container1", + "container1Link") })); + } + + @Test + public void createContainerWithCapAddAndCapDrop() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCapAdd(NET_ADMIN) + .withCapDrop(MKNOD).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getCapAdd()), contains(NET_ADMIN)); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getCapDrop()), contains(MKNOD)); + } + + @Test + public void createContainerWithDns() throws DockerException { + + String aDnsServer = "8.8.8.8"; + String anotherDnsServer = "8.8.4.4"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withDns(aDnsServer, anotherDnsServer).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDns()), + contains(aDnsServer, anotherDnsServer)); + } + + @Test + public void createContainerWithEntrypoint() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withName("container") + .withEntrypoint("sleep", "9999").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getConfig().getEntrypoint()), contains("sleep", "9999")); + + } + + @Test + public void createContainerWithExtraHosts() throws DockerException { + + String[] extraHosts = { "dockerhost:127.0.0.1", "otherhost:10.0.0.1" }; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withName("container") + .withExtraHosts(extraHosts).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getExtraHosts()), + containsInAnyOrder("dockerhost:127.0.0.1", "otherhost:10.0.0.1")); + } + + @Test + public void createContainerWithDevices() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withDevices(new Device("rwm", "/dev/nulo", "/dev/zero")).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDevices()), contains(new Device("rwm", + "/dev/nulo", "/dev/zero"))); + } + + @Test + public void createContainerWithPortBindings() throws DockerException { + + ExposedPort tcp22 = ExposedPort.tcp(22); + ExposedPort tcp23 = ExposedPort.tcp(23); + + Ports portBindings = new Ports(); + portBindings.bind(tcp22, Ports.Binding(11022)); + portBindings.bind(tcp23, Ports.Binding(11023)); + portBindings.bind(tcp23, Ports.Binding(11024)); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23)); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp22)[0], + is(equalTo(Ports.Binding(11022)))); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[0], + is(equalTo(Ports.Binding(11023)))); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[1], + is(equalTo(Ports.Binding(11024)))); + + } + + @Test + public void createContainerWithLinking() throws DockerException { + + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container1").exec(); + + LOG.info("Created container1 {}", container1.toString()); + assertThat(container1.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + LOG.info("Container1 Inspect: {}", inspectContainerResponse1.toString()); + + assertThat(inspectContainerResponse1.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse1.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getId(), startsWith(container1.getId())); + assertThat(inspectContainerResponse1.getName(), equalTo("/container1")); + assertThat(inspectContainerResponse1.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getState(), is(notNullValue())); + assertThat(inspectContainerResponse1.getState().getRunning(), is(true)); + + if (!inspectContainerResponse1.getState().getRunning()) { + assertThat(inspectContainerResponse1.getState().getExitCode(), is(equalTo(0))); + } + + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container2").withLinks(new Link("container1", "container1Link")).exec(); + + LOG.info("Created container2 {}", container2.toString()); + assertThat(container2.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + LOG.info("Container2 Inspect: {}", inspectContainerResponse2.toString()); + + assertThat(inspectContainerResponse2.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse2.getHostConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), equalTo(new Link[] { new Link("container1", + "container1Link") })); + assertThat(inspectContainerResponse2.getId(), startsWith(container2.getId())); + assertThat(inspectContainerResponse2.getName(), equalTo("/container2")); + assertThat(inspectContainerResponse2.getImageId(), not(isEmptyString())); + + } + + @Test + public void createContainerWithRestartPolicy() throws DockerException { + + RestartPolicy restartPolicy = RestartPolicy.onFailureRestart(5); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withRestartPolicy(restartPolicy).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getRestartPolicy(), is(equalTo(restartPolicy))); + } + + @Test + public void createContainerWithPidMode() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withPidMode("host").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getPidMode(), is(equalTo("host"))); + } + + /** + * This tests support for --net option for the docker run command: --net="bridge" Set the Network mode for the + * container 'bridge': creates a new network stack for the container on the docker bridge 'none': no networking for + * this container 'container:': reuses another container network stack 'host': use the host network stack inside the + * container. Note: the host mode gives the container full access to local system services such as D-bus and is + * therefore considered insecure. + */ + @Test + public void createContainerWithNetworkMode() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withNetworkMode("host").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getNetworkMode(), is(equalTo("host"))); + } + + @Test + public void createContainerWithMacAddress() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox") + .withMacAddress("00:80:41:ae:fd:7e").withCmd("true").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertEquals(inspectContainerResponse.getConfig().getMacAddress(), "00:80:41:ae:fd:7e"); + } + + @Test(groups = "ignoreInCircleCi") + public void createContainerWithULimits() throws DockerException { + + Ulimit[] ulimits = { new Ulimit("nproc", 709, 1026), new Ulimit("nofile", 1024, 4096) }; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withName("container") + .withUlimits(ulimits).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getUlimits()), + containsInAnyOrder(new Ulimit("nproc", 709, 1026), new Ulimit("nofile", 1024, 4096))); + + } + + @Test(groups = "ignoreInCircleCi") + public void createContainerWithLabels() throws DockerException { + + Map labels = new HashMap(); + labels.put("com.github.dockerjava.null", null); + labels.put("com.github.dockerjava.Boolean", "true"); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withLabels(labels).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + // null becomes empty string + labels.put("com.github.dockerjava.null", ""); + assertThat(inspectContainerResponse.getConfig().getLabels(), is(equalTo(labels))); + } + + @Test(groups = "ignoreInCircleCi") + public void createContainerWithLogConfig() throws DockerException { + + LogConfig logConfig = new LogConfig(LogConfig.LoggingType.NONE, null); + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withLogConfig(logConfig).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + // null becomes empty string + assertEquals(inspectContainerResponse.getHostConfig().getLogConfig().type, logConfig.type); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/EventsCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/EventsCmdExecTest.java new file mode 100644 index 000000000..06119b203 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/EventsCmdExecTest.java @@ -0,0 +1,162 @@ +package com.github.dockerjava.netty.exec; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.model.Event; +import com.github.dockerjava.api.model.EventFilters; +import com.github.dockerjava.core.command.EventsResultCallback; +import com.github.dockerjava.core.command.PullImageResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class EventsCmdExecTest extends AbstractNettyDockerClientTest { + + private static int KNOWN_NUM_EVENTS = 4; + + private static String getEpochTime() { + return String.valueOf(System.currentTimeMillis() / 1000); + } + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + /* + * This specific test may fail with boot2docker as time may not in sync with host system + */ + @Test + public void testEventStreamTimeBound() throws Exception { + // Don't include other tests events + TimeUnit.SECONDS.sleep(1); + + String startTime = getEpochTime(); + int expectedEvents = generateEvents(); + String endTime = getEpochTime(); + + CountDownLatch countDownLatch = new CountDownLatch(expectedEvents); + EventsTestCallback eventCallback = new EventsTestCallback(countDownLatch); + + dockerClient.eventsCmd().withSince(startTime).withUntil(endTime).exec(eventCallback); + + Boolean zeroCount = countDownLatch.await(10, TimeUnit.SECONDS); + + eventCallback.close(); + + assertTrue(zeroCount, "Received only: " + eventCallback.getEvents()); + } + + @Test + public void testEventStreaming1() throws Exception { + // Don't include other tests events + TimeUnit.SECONDS.sleep(1); + + CountDownLatch countDownLatch = new CountDownLatch(KNOWN_NUM_EVENTS); + EventsTestCallback eventCallback = new EventsTestCallback(countDownLatch); + + dockerClient.eventsCmd().withSince(getEpochTime()).exec(eventCallback); + + generateEvents(); + + Boolean zeroCount = countDownLatch.await(10, TimeUnit.SECONDS); + + eventCallback.close(); + assertTrue(zeroCount, "Received only: " + eventCallback.getEvents()); + } + + @Test + public void testEventStreaming2() throws Exception { + // Don't include other tests events + TimeUnit.SECONDS.sleep(1); + + CountDownLatch countDownLatch = new CountDownLatch(KNOWN_NUM_EVENTS); + EventsTestCallback eventCallback = new EventsTestCallback(countDownLatch); + + dockerClient.eventsCmd().withSince(getEpochTime()).exec(eventCallback); + + generateEvents(); + + Boolean zeroCount = countDownLatch.await(10, TimeUnit.SECONDS); + + eventCallback.close(); + assertTrue(zeroCount, "Received only: " + eventCallback.getEvents()); + } + + public void testEventStreamingWithFilter() throws Exception { + // Don't include other tests events + TimeUnit.SECONDS.sleep(1); + + CountDownLatch countDownLatch = new CountDownLatch(1); + EventsTestCallback eventCallback = dockerClient.eventsCmd().withFilters(new EventFilters().withEvent("start")) + .exec(new EventsTestCallback(countDownLatch)); + + generateEvents(); + + Boolean zeroCount = countDownLatch.await(10, TimeUnit.SECONDS); + + eventCallback.close(); + assertTrue(zeroCount, "Received only: " + eventCallback.getEvents()); + } + + /** + * This method generates {#link KNOWN_NUM_EVENTS} events + */ + private int generateEvents() throws Exception { + String testImage = "busybox"; + + dockerClient.pullImageCmd(testImage).exec(new PullImageResultCallback()).awaitSuccess(); + + CreateContainerResponse container = dockerClient.createContainerCmd(testImage).withCmd("sleep", "9999").exec(); + dockerClient.startContainerCmd(container.getId()).exec(); + dockerClient.stopContainerCmd(container.getId()).exec(); + return KNOWN_NUM_EVENTS; + } + + private class EventsTestCallback extends EventsResultCallback { + + private final CountDownLatch countDownLatch; + + private final List events = new ArrayList(); + + public EventsTestCallback(CountDownLatch countDownLatch) { + this.countDownLatch = countDownLatch; + } + + public void onNext(Event event) { + LOG.info("Received event #{}: {}", countDownLatch.getCount(), event); + countDownLatch.countDown(); + events.add(event); + } + + public List getEvents() { + return new ArrayList(events); + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/ExecCreateCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/ExecCreateCmdExecTest.java new file mode 100644 index 000000000..d0ec28ac9 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/ExecCreateCmdExecTest.java @@ -0,0 +1,61 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; +import java.security.SecureRandom; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class ExecCreateCmdExecTest extends AbstractNettyDockerClientTest { + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void execCreateTest() { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.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()) + .withCmd("touch", "file.log").exec(); + + assertThat(execCreateCmdResponse.getId(), not(isEmptyString())); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/ExecStartCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/ExecStartCmdExecTest.java new file mode 100644 index 000000000..b9d81db9d --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/ExecStartCmdExecTest.java @@ -0,0 +1,146 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.security.SecureRandom; +import java.util.concurrent.TimeUnit; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class ExecStartCmdExecTest extends AbstractNettyDockerClientTest { + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void execStart() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.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", "/execStartTest.log").exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec( + new ExecStartResultCallback(System.out, System.err)); + + 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); + } + + @Test(groups = "ignoreInCircleCi") + public void execStartAttached() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .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", "/execStartTest.log").exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).withDetach(false).withTty(true) + .exec(new ExecStartResultCallback(System.out, System.err)); + + 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); + } + + @Test(groups = "ignoreInCircleCi") + public void execStartAttachStdin() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName(containerName).exec(); + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InputStream stdin = new ByteArrayInputStream("echo STDIN\n".getBytes()); + + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + + ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()) + .withAttachStdout(true).withAttachStdin(true).withCmd("/bin/sh").exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).withDetach(false).withTty(true).withStdIn(stdin) + .exec(new ExecStartResultCallback(stdout, System.err)).awaitCompletion(5, TimeUnit.SECONDS); + + assertEquals(stdout.toString(), "STDIN\n"); + } + + @Test(groups = "ignoreInCircleCi") + public void execStartNotAttachedStdin() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName(containerName).exec(); + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InputStream stdin = new ByteArrayInputStream("echo STDIN\n".getBytes()); + + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + + ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()) + .withAttachStdout(true).withAttachStdin(false).withCmd("/bin/sh").exec(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).withDetach(false).withTty(true).withStdIn(stdin) + .exec(new ExecStartResultCallback(stdout, System.err)).awaitCompletion(5, TimeUnit.SECONDS); + + assertEquals(stdout.toString(), ""); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/InfoCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/InfoCmdExecTest.java new file mode 100644 index 000000000..850f98a74 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/InfoCmdExecTest.java @@ -0,0 +1,71 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class InfoCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + 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").exec(); + + LOG.info("Created container: {}", container); + assertThat(container.getId(), not(isEmptyOrNullString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + } + + Info dockerInfo = dockerClient.infoCmd().exec(); + LOG.info(dockerInfo.toString()); + + assertTrue(dockerInfo.toString().contains("containers")); + assertTrue(dockerInfo.toString().contains("images")); + assertTrue(dockerInfo.toString().contains("debug")); + + assertTrue(dockerInfo.getContainers() > 0); + assertTrue(dockerInfo.getImages() > 0); + assertTrue(dockerInfo.getNFd() > 0); + assertTrue(dockerInfo.getNGoroutines() > 0); + assertTrue(dockerInfo.getNCPU() > 0); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/InspectContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/InspectContainerCmdExecTest.java new file mode 100644 index 000000000..63bafe7d2 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/InspectContainerCmdExecTest.java @@ -0,0 +1,75 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; +import java.security.SecureRandom; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class InspectContainerCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(InspectContainerCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test() + public void inspectContainer() throws DockerException { + + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("top") + .withName(containerName).exec(); + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(container.getId()).exec(); + assertEquals(containerInfo.getId(), container.getId()); + + } + + @Test + public void inspectNonExistingContainer() throws DockerException { + + try { + dockerClient.inspectContainerCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/InspectExecCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/InspectExecCmdExecTest.java new file mode 100644 index 000000000..fc3bb089b --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/InspectExecCmdExecTest.java @@ -0,0 +1,100 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.SecureRandom; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.InspectExecResponse; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; +import com.github.dockerjava.test.serdes.JSONTestHelper; + +@Test(groups = "integration") +public class InspectExecCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void inspectExecTest() throws IOException { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("top") + .withName(containerName).exec(); + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + ExecCreateCmdResponse touchFileCmdCreateResponse = dockerClient.execCreateCmd(container.getId()) + .withAttachStdout(true).withAttachStderr(true).withCmd("touch", "/marker").withTty(true).exec(); + LOG.info("Created exec {}", touchFileCmdCreateResponse.toString()); + assertThat(touchFileCmdCreateResponse.getId(), not(isEmptyString())); + ExecCreateCmdResponse checkFileCmdCreateResponse = dockerClient.execCreateCmd(container.getId()) + .withAttachStdout(true).withAttachStderr(true).withCmd("test", "-e", "/marker").exec(); + LOG.info("Created exec {}", checkFileCmdCreateResponse.toString()); + assertThat(checkFileCmdCreateResponse.getId(), not(isEmptyString())); + + // Check that file does not exist + dockerClient.execStartCmd(container.getId()).withDetach(false).withTty(true) + .withExecId(checkFileCmdCreateResponse.getId()) + .exec(new ExecStartResultCallback(System.out, System.err)); + + InspectExecResponse first = dockerClient.inspectExecCmd(checkFileCmdCreateResponse.getId()).exec(); + assertEquals(first.isRunning(), new Boolean(false)); + assertThat(first.getExitCode(), is(1)); + + // Create the file + dockerClient.execStartCmd(container.getId()).withDetach(false).withTty(true) + .withExecId(touchFileCmdCreateResponse.getId()) + .exec(new ExecStartResultCallback(System.out, System.err)); + + InspectExecResponse second = dockerClient.inspectExecCmd(touchFileCmdCreateResponse.getId()).exec(); + assertEquals(first.isRunning(), new Boolean(false)); + assertThat(second.getExitCode(), is(0)); + + // Check that file does exist now + dockerClient.execStartCmd(container.getId()).withExecId(checkFileCmdCreateResponse.getId()) + .exec(new ExecStartResultCallback(System.out, System.err)); + + InspectExecResponse third = dockerClient.inspectExecCmd(checkFileCmdCreateResponse.getId()).exec(); + assertThat(third.getExitCode(), is(0)); + + // Get container info and check its roundtrip to ensure the consistency + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(container.getId()).exec(); + assertEquals(containerInfo.getId(), container.getId()); + JSONTestHelper.testRoundTrip(containerInfo); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/KillContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/KillContainerCmdExecTest.java new file mode 100644 index 000000000..867373e63 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/KillContainerCmdExecTest.java @@ -0,0 +1,80 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class KillContainerCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(KillContainerCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void killContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + LOG.info("Killing container: {}", container.getId()); + dockerClient.killContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + assertThat(inspectContainerResponse.getState().getRunning(), is(equalTo(false))); + assertThat(inspectContainerResponse.getState().getExitCode(), not(equalTo(0))); + + } + + @Test + public void killNonExistingContainer() throws DockerException { + + try { + dockerClient.killContainerCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/ListContainersCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/ListContainersCmdExecTest.java new file mode 100644 index 000000000..c36bead2e --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/ListContainersCmdExecTest.java @@ -0,0 +1,171 @@ +package com.github.dockerjava.netty.exec; + +import static ch.lambdaj.Lambda.filter; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import org.hamcrest.Matcher; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.Filters; +import com.github.dockerjava.core.command.PullImageResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; +import com.google.common.collect.ImmutableMap; + +@Test(groups = "integration") +public class ListContainersCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + public void testListContainers() throws Exception { + + String testImage = "busybox"; + + // // need to block until image is pulled completely + // dockerClient.pullImageCmd(testImage).exec(new PullImageResultCallback()).awaitSuccess(); + + List containers = dockerClient.listContainersCmd().withShowAll(true).exec(); + assertThat(containers, notNullValue()); + LOG.info("Container List: {}", containers); + + int size = containers.size(); + + CreateContainerResponse container1 = dockerClient.createContainerCmd(testImage).withCmd("echo").exec(); + + assertThat(container1.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container1.getId()).exec(); + + assertThat(inspectContainerResponse.getConfig().getImage(), is(equalTo(testImage))); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + LOG.info("container id: " + container1.getId()); + + List containers2 = dockerClient.listContainersCmd().withShowAll(true).exec(); + + for (Container container : containers2) { + LOG.info("listContainer: id=" + container.getId() + " image=" + container.getImage()); + } + + assertThat(size + 1, is(equalTo(containers2.size()))); + Matcher matcher = hasItem(hasField("id", startsWith(container1.getId()))); + assertThat(containers2, matcher); + + List filteredContainers = filter(hasField("id", startsWith(container1.getId())), containers2); + assertThat(filteredContainers.size(), is(equalTo(1))); + + for (Container container : filteredContainers) { + LOG.info("filteredContainer: " + container); + } + + Container container2 = filteredContainers.get(0); + assertThat(container2.getCommand(), not(isEmptyString())); + assertThat(container2.getImage(), startsWith(testImage)); + } + + @Test + public void testListContainersWithLabelsFilter() throws Exception { + + String testImage = "busybox"; + + // need to block until image is pulled completely + dockerClient.pullImageCmd(testImage).exec(new PullImageResultCallback()).awaitCompletion(); + + List containers = dockerClient.listContainersCmd().withShowAll(true).exec(); + assertThat(containers, notNullValue()); + LOG.info("Container List: {}", containers); + + int size = containers.size(); + + CreateContainerResponse container1 = dockerClient.createContainerCmd(testImage).withCmd("echo").exec(); + + assertThat(container1.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container1.getId()).exec(); + + assertThat(inspectContainerResponse.getConfig().getImage(), is(equalTo(testImage))); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + LOG.info("container id: " + container1.getId()); + + List containers2 = dockerClient.listContainersCmd().withShowAll(true).exec(); + + for (Container container : containers2) { + LOG.info("listContainer: id=" + container.getId() + " image=" + container.getImage()); + } + + assertThat(size + 1, is(equalTo(containers2.size()))); + Matcher matcher = hasItem(hasField("id", startsWith(container1.getId()))); + assertThat(containers2, matcher); + + List filteredContainers = filter(hasField("id", startsWith(container1.getId())), containers2); + assertThat(filteredContainers.size(), is(equalTo(1))); + + for (Container container : filteredContainers) { + LOG.info("filteredContainer: " + container); + } + + Container container2 = filteredContainers.get(0); + assertThat(container2.getCommand(), not(isEmptyString())); + assertThat(container2.getImage(), startsWith(testImage)); + + Map labels = ImmutableMap.of("test", "docker-java"); + + // list with filter by label + dockerClient.createContainerCmd(testImage).withCmd("echo").withLabels(labels).exec(); + filteredContainers = dockerClient.listContainersCmd().withShowAll(true) + .withFilters(new Filters().withLabels(labels)).exec(); + assertThat(filteredContainers.size(), is(equalTo(1))); + Container container3 = filteredContainers.get(0); + assertThat(container3.getCommand(), not(isEmptyString())); + assertThat(container3.getImage(), startsWith(testImage)); + + filteredContainers = dockerClient.listContainersCmd().withShowAll(true) + .withFilters(new Filters().withLabels("test")).exec(); + assertThat(filteredContainers.size(), is(equalTo(1))); + container3 = filteredContainers.get(0); + assertThat(container3.getCommand(), not(isEmptyString())); + assertThat(container3.getImage(), startsWith(testImage)); + assertEquals(container3.getLabels(), labels); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/ListImagesCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/ListImagesCmdExecTest.java new file mode 100644 index 000000000..f6348c7d9 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/ListImagesCmdExecTest.java @@ -0,0 +1,102 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.emptyArray; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; + +import java.lang.reflect.Method; +import java.util.List; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.Image; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class ListImagesCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void listImages() throws DockerException { + List images = dockerClient.listImagesCmd().withShowAll(true).exec(); + assertThat(images, notNullValue()); + LOG.info("Images List: {}", images); + Info info = dockerClient.infoCmd().exec(); + + assertThat(images.size(), equalTo(info.getImages())); + + Image img = images.get(0); + assertThat(img.getCreated(), is(greaterThan(0L))); + assertThat(img.getVirtualSize(), is(greaterThan(0L))); + assertThat(img.getId(), not(isEmptyString())); + assertThat(img.getRepoTags(), not(emptyArray())); + } + + @Test(groups = "ignoreInCircleCi") + public void listDanglingImages() throws DockerException { + String imageId = createDanglingImage(); + List images = dockerClient.listImagesCmd().withFilters("{\"dangling\":[\"true\"]}").withShowAll(true) + .exec(); + assertThat(images, notNullValue()); + LOG.info("Images List: {}", images); + assertThat(images.size(), is(greaterThan(0))); + Boolean imageInFilteredList = isImageInFilteredList(images, imageId); + assertTrue(imageInFilteredList); + } + + private boolean isImageInFilteredList(List images, String expectedImageId) { + for (Image image : images) { + if (expectedImageId.equals(image.getId())) { + return true; + } + } + return false; + } + + private String createDanglingImage() { + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "5").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + LOG.info("Committing container {}", container.toString()); + String imageId = dockerClient.commitCmd(container.getId()).exec(); + + dockerClient.stopContainerCmd(container.getId()).exec(); + dockerClient.killContainerCmd(container.getId()).exec(); + dockerClient.removeContainerCmd(container.getId()).exec(); + return imageId; + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/LogContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/LogContainerCmdExecTest.java new file mode 100644 index 000000000..b3bb6ed58 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/LogContainerCmdExecTest.java @@ -0,0 +1,171 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class LogContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void asyncLogContainer() throws Exception { + + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("/bin/echo", snippet) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()) + .awaitStatusCode(); + + assertThat(exitCode, equalTo(0)); + + LogContainerTestCallback loggingCallback = new LogContainerTestCallback(); + + // this essentially test the since=0 case + dockerClient.logContainerCmd(container.getId()).withStdErr(true).withStdOut(true).exec(loggingCallback); + + loggingCallback.awaitCompletion(); + + assertTrue(loggingCallback.toString().contains(snippet)); + } + + @Test + public void asyncLogNonExistingContainer() throws Exception { + + LogContainerTestCallback loggingCallback = new LogContainerTestCallback() { + @Override + public void onError(Throwable throwable) { + + assertEquals(throwable.getClass().getName(), NotFoundException.class.getName()); + + try { + // close the callback to prevent the call to onComplete + close(); + } catch (IOException e) { + throw new RuntimeException(); + } + + super.onError(throwable); + } + + public void onComplete() { + super.onComplete(); + fail("expected NotFoundException"); + }; + }; + + dockerClient.logContainerCmd("non-existing").withStdErr(true).withStdOut(true).exec(loggingCallback) + .awaitCompletion(); + } + + @Test + public void asyncMultipleLogContainer() throws Exception { + + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("/bin/echo", snippet) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()) + .awaitStatusCode(); + + assertThat(exitCode, equalTo(0)); + + LogContainerTestCallback loggingCallback = new LogContainerTestCallback(); + + dockerClient.logContainerCmd(container.getId()).withStdErr(true).withStdOut(true).exec(loggingCallback); + + loggingCallback.close(); + + loggingCallback = new LogContainerTestCallback(); + + dockerClient.logContainerCmd(container.getId()).withStdErr(true).withStdOut(true).exec(loggingCallback); + + loggingCallback.close(); + + loggingCallback = new LogContainerTestCallback(); + + dockerClient.logContainerCmd(container.getId()).withStdErr(true).withStdOut(true).exec(loggingCallback); + + loggingCallback.awaitCompletion(); + + assertTrue(loggingCallback.toString().contains(snippet)); + } + + @Test + public void asyncLogContainerWithSince() throws Exception { + String snippet = "hello world"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("/bin/echo", snippet) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + int timestamp = (int) (System.currentTimeMillis() / 1000); + + dockerClient.startContainerCmd(container.getId()).exec(); + + int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()) + .awaitStatusCode(); + + assertThat(exitCode, equalTo(0)); + + LogContainerTestCallback loggingCallback = new LogContainerTestCallback(); + + dockerClient.logContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withSince(timestamp) + .exec(loggingCallback); + + loggingCallback.awaitCompletion(); + + assertFalse(loggingCallback.toString().contains(snippet)); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/PingCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/PingCmdExecTest.java new file mode 100644 index 000000000..128c1969a --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/PingCmdExecTest.java @@ -0,0 +1,43 @@ +package com.github.dockerjava.netty.exec; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class PingCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void ping() throws DockerException { + dockerClient.pingCmd().exec(); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/PullImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/PullImageCmdExecTest.java new file mode 100644 index 000000000..53fa8d660 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/PullImageCmdExecTest.java @@ -0,0 +1,119 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.notNullValue; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.PullResponseItem; +import com.github.dockerjava.core.command.PullImageCmdImpl; +import com.github.dockerjava.core.command.PullImageResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class PullImageCmdExecTest extends AbstractNettyDockerClientTest { + + private static final PullImageCmd.Exec NOP_EXEC = new PullImageCmd.Exec() { + public Void exec(PullImageCmd command, ResultCallback resultCallback) { + return null; + }; + }; + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void nullAuthConfig() throws Exception { + PullImageCmdImpl pullImageCmd = new PullImageCmdImpl(NOP_EXEC, null, ""); + try { + pullImageCmd.withAuthConfig(null); + fail(); + } catch (Exception e) { + assertEquals(e.getMessage(), "authConfig was not specified"); + } finally { + pullImageCmd.close(); + } + } + + @Test + public void testPullImage() throws Exception { + Info info = dockerClient.infoCmd().exec(); + LOG.info("Client info: {}", info.toString()); + + int imgCount = info.getImages(); + LOG.info("imgCount1: {}", imgCount); + + // This should be an image that is not used by other repositories + // already + // pulled down, preferably small in size. If tag is not used pull will + // download all images in that repository but tmpImgs will only + // deleted 'latest' image but not images with other tags + String testImage = "hackmann/empty"; + + LOG.info("Removing image: {}", testImage); + + try { + dockerClient.removeImageCmd(testImage).withForce(true).exec(); + } catch (NotFoundException e) { + // just ignore if not exist + } + + info = dockerClient.infoCmd().exec(); + LOG.info("Client info: {}", info.toString()); + + imgCount = info.getImages(); + LOG.info("imgCount2: {}", imgCount); + + LOG.info("Pulling image: {}", testImage); + + dockerClient.pullImageCmd(testImage).exec(new PullImageResultCallback()).awaitSuccess(); + + info = dockerClient.infoCmd().exec(); + LOG.info("Client info after pull, {}", info.toString()); + + assertThat(imgCount, lessThanOrEqualTo(info.getImages())); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(testImage).exec(); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + assertThat(inspectImageResponse, notNullValue()); + } + + @Test + public void testPullNonExistingImage() throws Exception { + + // does not throw an exception + // stream needs to be fully read in order to close the underlying connection + dockerClient.pullImageCmd("xvxcv/foo").exec(new PullImageResultCallback()).awaitCompletion(); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/PushImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/PushImageCmdExecTest.java new file mode 100644 index 000000000..777cc8eed --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/PushImageCmdExecTest.java @@ -0,0 +1,79 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.core.command.PullImageResultCallback; +import com.github.dockerjava.core.command.PushImageResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class PushImageCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(PushImageCmdExecTest.class); + + String username; + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + username = dockerClient.authConfig().getUsername(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void pushLatest() throws Exception { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + LOG.info("Committing container: {}", container.toString()); + String imageId = dockerClient.commitCmd(container.getId()).withRepository(username + "/busybox").exec(); + + // we have to block until image is pushed + dockerClient.pushImageCmd(username + "/busybox").exec(new PushImageResultCallback()).awaitSuccess(); + + LOG.info("Removing image: {}", imageId); + dockerClient.removeImageCmd(imageId).exec(); + + dockerClient.pullImageCmd(username + "/busybox").exec(new PullImageResultCallback()).awaitSuccess(); + } + + @Test(expectedExceptions = DockerClientException.class) + public void pushNonExistentImage() throws Exception { + + dockerClient.pushImageCmd(username + "/xxx").exec(new PushImageResultCallback()).awaitSuccess(); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExecTest.java new file mode 100644 index 000000000..ffe456c09 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExecTest.java @@ -0,0 +1,81 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; +import java.util.List; + +import org.hamcrest.Matcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class RemoveContainerCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(RemoveContainerCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void removeContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true").exec(); + + dockerClient.startContainerCmd(container.getId()).exec(); + dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode(); + + LOG.info("Removing container: {}", container.getId()); + dockerClient.removeContainerCmd(container.getId()).exec(); + + List containers2 = dockerClient.listContainersCmd().withShowAll(true).exec(); + + Matcher matcher = not(hasItem(hasField("id", startsWith(container.getId())))); + assertThat(containers2, matcher); + + } + + @Test + public void removeNonExistingContainer() throws DockerException { + try { + dockerClient.removeContainerCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/RemoveImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/RemoveImageCmdExecTest.java new file mode 100644 index 000000000..62ff486ea --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/RemoveImageCmdExecTest.java @@ -0,0 +1,88 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; +import java.util.List; + +import org.hamcrest.Matcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class RemoveImageCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(RemoveImageCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void removeImage() throws DockerException, InterruptedException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + LOG.info("Committing container {}", container.toString()); + String imageId = dockerClient.commitCmd(container.getId()).exec(); + + dockerClient.stopContainerCmd(container.getId()).exec(); + dockerClient.killContainerCmd(container.getId()).exec(); + dockerClient.removeContainerCmd(container.getId()).exec(); + + LOG.info("Removing image: {}", imageId); + dockerClient.removeImageCmd(imageId).exec(); + + List containers = dockerClient.listContainersCmd().withShowAll(true).exec(); + + Matcher matcher = not(hasItem(hasField("id", startsWith(imageId)))); + assertThat(containers, matcher); + } + + @Test + public void removeNonExistingImage() throws DockerException, InterruptedException { + try { + dockerClient.removeImageCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/RestartContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/RestartContainerCmdExecTest.java new file mode 100644 index 000000000..3360057a8 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/RestartContainerCmdExecTest.java @@ -0,0 +1,84 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class RestartContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void restartContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + String startTime = inspectContainerResponse.getState().getStartedAt(); + + dockerClient.restartContainerCmd(container.getId()).withtTimeout(2).exec(); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect After Restart: {}", inspectContainerResponse2.toString()); + + String startTime2 = inspectContainerResponse2.getState().getStartedAt(); + + assertThat(startTime, not(equalTo(startTime2))); + + assertThat(inspectContainerResponse.getState().getRunning(), is(equalTo(true))); + + dockerClient.killContainerCmd(container.getId()).exec(); + } + + @Test + public void restartNonExistingContainer() throws DockerException, InterruptedException { + try { + dockerClient.restartContainerCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/SaveImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/SaveImageCmdExecTest.java new file mode 100644 index 000000000..0527b793f --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/SaveImageCmdExecTest.java @@ -0,0 +1,55 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import java.io.InputStream; +import java.lang.reflect.Method; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class SaveImageCmdExecTest extends AbstractNettyDockerClientTest { + public static final Logger LOG = LoggerFactory.getLogger(SaveImageCmdExecTest.class); + + String username; + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void saveImage() throws Exception { + + InputStream image = IOUtils.toBufferedInputStream(dockerClient.saveImageCmd("busybox").exec()); + assertThat(image.available(), greaterThan(0)); + + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/SearchImagesCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/SearchImagesCmdExecTest.java new file mode 100644 index 000000000..70e102335 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/SearchImagesCmdExecTest.java @@ -0,0 +1,59 @@ +package com.github.dockerjava.netty.exec; + +import static ch.lambdaj.Lambda.filter; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField; + +import java.lang.reflect.Method; +import java.util.List; + +import org.hamcrest.Matcher; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.SearchItem; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class SearchImagesCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void searchImages() throws DockerException { + List dockerSearch = dockerClient.searchImagesCmd("busybox").exec(); + LOG.info("Search returned {}", dockerSearch.toString()); + + Matcher matcher = hasItem(hasField("name", equalTo("busybox"))); + assertThat(dockerSearch, matcher); + + assertThat(filter(hasField("name", is("busybox")), dockerSearch).size(), equalTo(1)); + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/StartContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/StartContainerCmdExecTest.java new file mode 100644 index 000000000..d743935eb --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/StartContainerCmdExecTest.java @@ -0,0 +1,560 @@ +package com.github.dockerjava.netty.exec; + +import static com.github.dockerjava.api.model.AccessMode.ro; +import static com.github.dockerjava.api.model.Capability.MKNOD; +import static com.github.dockerjava.api.model.Capability.NET_ADMIN; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.UUID; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.InternalServerErrorException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.AccessMode; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Device; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.Link; +import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.RestartPolicy; +import com.github.dockerjava.api.model.Volume; +import com.github.dockerjava.api.model.VolumeRW; +import com.github.dockerjava.api.model.VolumesFrom; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class StartContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void startContainerWithVolumes() throws DockerException { + + // see http://docs.docker.io/use/working_with_volumes/ + Volume volume1 = new Volume("/opt/webapp1"); + + Volume volume2 = new Volume("/opt/webapp2"); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withVolumes(volume1, volume2) + .withCmd("true").withBinds(new Bind("/src/webapp1", volume1, ro), new Bind("/src/webapp2", volume2)) + .exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getConfig().getVolumes().keySet(), contains("/opt/webapp1", "/opt/webapp2")); + + dockerClient.startContainerCmd(container.getId()).exec(); + + dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode(); + + inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse, mountedVolumes(containsInAnyOrder(volume1, volume2))); + + assertThat(inspectContainerResponse.getMounts().size(), equalTo(2)); + + assertThat(inspectContainerResponse.getMounts().get(0).getDestination(), equalTo(volume1)); + assertThat(inspectContainerResponse.getMounts().get(0).getMode(), equalTo("ro")); + assertThat(inspectContainerResponse.getMounts().get(0).getRW(), equalTo(Boolean.FALSE)); + + assertThat(inspectContainerResponse.getMounts().get(1).getDestination(), equalTo(volume2)); + assertThat(inspectContainerResponse.getMounts().get(1).getMode(), equalTo("rw")); + assertThat(inspectContainerResponse.getMounts().get(1).getRW(), equalTo(Boolean.TRUE)); + } + + @Test + public void startContainerWithVolumesFrom() throws DockerException { + + Volume volume1 = new Volume("/opt/webapp1"); + Volume volume2 = new Volume("/opt/webapp2"); + + String container1Name = UUID.randomUUID().toString(); + + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName(container1Name) + .withBinds(new Bind("/src/webapp1", volume1), new Bind("/src/webapp2", volume2)).exec(); + LOG.info("Created container1 {}", container1.toString()); + + dockerClient.startContainerCmd(container1.getId()).exec(); + LOG.info("Started container1 {}", container1.toString()); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + + assertThat(inspectContainerResponse1, mountedVolumes(containsInAnyOrder(volume1, volume2))); + + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withVolumesFrom(new VolumesFrom(container1Name)).exec(); + LOG.info("Created container2 {}", container2.toString()); + + dockerClient.startContainerCmd(container2.getId()).exec(); + LOG.info("Started container2 {}", container2.toString()); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + + assertThat(inspectContainerResponse2, mountedVolumes(containsInAnyOrder(volume1, volume2))); + } + + @Test + public void startContainerWithDns() throws DockerException { + + String aDnsServer = "8.8.8.8"; + String anotherDnsServer = "8.8.4.4"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withDns(aDnsServer, anotherDnsServer).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDns()), + contains(aDnsServer, anotherDnsServer)); + } + + @Test + public void startContainerWithDnsSearch() throws DockerException { + + String dnsSearch = "example.com"; + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withDnsSearch(dnsSearch).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + dockerClient.startContainerCmd(container.getId()).exec(); + + inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDnsSearch()), contains(dnsSearch)); + } + + @Test + public void startContainerWithPortBindings() throws DockerException { + + ExposedPort tcp22 = ExposedPort.tcp(22); + ExposedPort tcp23 = ExposedPort.tcp(23); + + Ports portBindings = new Ports(); + portBindings.bind(tcp22, Ports.Binding(11022)); + portBindings.bind(tcp23, Ports.Binding(11023)); + portBindings.bind(tcp23, Ports.Binding(11024)); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + dockerClient.startContainerCmd(container.getId()).exec(); + + inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23)); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp22)[0], + is(equalTo(Ports.Binding(11022)))); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[0], + is(equalTo(Ports.Binding(11023)))); + + assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[1], + is(equalTo(Ports.Binding(11024)))); + + } + + @Test + public void startContainerWithRandomPortBindings() throws DockerException { + + ExposedPort tcp22 = ExposedPort.tcp(22); + ExposedPort tcp23 = ExposedPort.tcp(23); + + Ports portBindings = new Ports(); + portBindings.bind(tcp22, Ports.Binding(null)); + portBindings.bind(tcp23, Ports.Binding(null)); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).withPublishAllPorts(true).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23)); + + assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp22)[0].getHostPort(), + is(not(equalTo(tcp22.getPort())))); + + assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp23)[0].getHostPort(), + is(not(equalTo(tcp23.getPort())))); + + } + + @Test + public void startContainerWithConflictingPortBindings() throws DockerException { + + ExposedPort tcp22 = ExposedPort.tcp(22); + ExposedPort tcp23 = ExposedPort.tcp(23); + + Ports portBindings = new Ports(); + portBindings.bind(tcp22, Ports.Binding(11022)); + portBindings.bind(tcp23, Ports.Binding(11022)); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + try { + dockerClient.startContainerCmd(container.getId()).exec(); + fail("expected InternalServerErrorException"); + } catch (InternalServerErrorException e) { + + } + + } + + @Test + public void startContainerWithLinkingDeprecated() throws DockerException { + + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container1").exec(); + + LOG.info("Created container1 {}", container1.toString()); + assertThat(container1.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + LOG.info("Container1 Inspect: {}", inspectContainerResponse1.toString()); + + assertThat(inspectContainerResponse1.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse1.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getId(), startsWith(container1.getId())); + assertThat(inspectContainerResponse1.getName(), equalTo("/container1")); + assertThat(inspectContainerResponse1.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getState(), is(notNullValue())); + assertThat(inspectContainerResponse1.getState().getRunning(), is(true)); + + if (!inspectContainerResponse1.getState().getRunning()) { + assertThat(inspectContainerResponse1.getState().getExitCode(), is(equalTo(0))); + } + + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container2").withLinks(new Link("container1", "container1Link")).exec(); + + LOG.info("Created container2 {}", container2.toString()); + assertThat(container2.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container2.getId()).exec(); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + LOG.info("Container2 Inspect: {}", inspectContainerResponse2.toString()); + + assertThat(inspectContainerResponse2.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse2.getHostConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), equalTo(new Link[] { new Link("container1", + "container1Link") })); + assertThat(inspectContainerResponse2.getId(), startsWith(container2.getId())); + assertThat(inspectContainerResponse2.getName(), equalTo("/container2")); + assertThat(inspectContainerResponse2.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse2.getState(), is(notNullValue())); + assertThat(inspectContainerResponse2.getState().getRunning(), is(true)); + + } + + @Test + public void startContainerWithLinking() throws DockerException { + + CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container1").exec(); + + LOG.info("Created container1 {}", container1.toString()); + assertThat(container1.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container1.getId()).exec(); + + InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) + .exec(); + LOG.info("Container1 Inspect: {}", inspectContainerResponse1.toString()); + + assertThat(inspectContainerResponse1.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse1.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getId(), startsWith(container1.getId())); + assertThat(inspectContainerResponse1.getName(), equalTo("/container1")); + assertThat(inspectContainerResponse1.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse1.getState(), is(notNullValue())); + assertThat(inspectContainerResponse1.getState().getRunning(), is(true)); + + if (!inspectContainerResponse1.getState().getRunning()) { + assertThat(inspectContainerResponse1.getState().getExitCode(), is(equalTo(0))); + } + + CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withName("container2").withLinks(new Link("container1", "container1Link")).exec(); + + LOG.info("Created container2 {}", container2.toString()); + assertThat(container2.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container2.getId()).exec(); + + InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) + .exec(); + LOG.info("Container2 Inspect: {}", inspectContainerResponse2.toString()); + + assertThat(inspectContainerResponse2.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getId(), not(isEmptyString())); + assertThat(inspectContainerResponse2.getHostConfig(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), is(notNullValue())); + assertThat(inspectContainerResponse2.getHostConfig().getLinks(), equalTo(new Link[] { new Link("container1", + "container1Link") })); + assertThat(inspectContainerResponse2.getId(), startsWith(container2.getId())); + assertThat(inspectContainerResponse2.getName(), equalTo("/container2")); + assertThat(inspectContainerResponse2.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse2.getState(), is(notNullValue())); + assertThat(inspectContainerResponse2.getState().getRunning(), is(true)); + + } + + @Test + public void startContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd(new String[] { "top" }) + .exec(); + + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + assertThat(inspectContainerResponse.getConfig(), is(notNullValue())); + assertThat(inspectContainerResponse.getId(), not(isEmptyString())); + + assertThat(inspectContainerResponse.getId(), startsWith(container.getId())); + + assertThat(inspectContainerResponse.getImageId(), not(isEmptyString())); + assertThat(inspectContainerResponse.getState(), is(notNullValue())); + + assertThat(inspectContainerResponse.getState().getRunning(), is(true)); + + if (!inspectContainerResponse.getState().getRunning()) { + assertThat(inspectContainerResponse.getState().getExitCode(), is(equalTo(0))); + } + } + + @Test + public void testStartNonExistingContainer() throws DockerException { + try { + dockerClient.startContainerCmd("non-existing").exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + + /** + * This tests support for --net option for the docker run command: --net="bridge" Set the Network mode for the + * container 'bridge': creates a new network stack for the container on the docker bridge 'none': no networking for + * this container 'container:': reuses another container network stack 'host': use the host network stack inside the + * container. Note: the host mode gives the container full access to local system services such as D-bus and is + * therefore considered insecure. + */ + @Test + public void startContainerWithNetworkMode() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true") + .withNetworkMode("host").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + dockerClient.startContainerCmd(container.getId()).exec(); + + inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getNetworkMode(), is(equalTo("host"))); + } + + @Test + public void startContainerWithCapAddAndCapDrop() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withCapAdd(NET_ADMIN).withCapDrop(MKNOD).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getState().getRunning(), is(true)); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getCapAdd()), contains(NET_ADMIN)); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getCapDrop()), contains(MKNOD)); + } + + @Test + public void startContainerWithDevices() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withDevices(new Device("rwm", "/dev/nulo", "/dev/zero")).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getState().getRunning(), is(true)); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDevices()), contains(new Device("rwm", + "/dev/nulo", "/dev/zero"))); + } + + @Test + public void startContainerWithExtraHosts() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withExtraHosts("dockerhost:127.0.0.1").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getState().getRunning(), is(true)); + + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getExtraHosts()), + contains("dockerhost:127.0.0.1")); + } + + @Test + public void startContainerWithRestartPolicy() throws DockerException { + + RestartPolicy restartPolicy = RestartPolicy.onFailureRestart(5); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") + .withRestartPolicy(restartPolicy).exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getState().getRunning(), is(true)); + + assertThat(inspectContainerResponse.getHostConfig().getRestartPolicy(), is(equalTo(restartPolicy))); + } + + @Test + public void existingHostConfigIsPreservedByBlankStartCmd() throws DockerException { + + String dnsServer = "8.8.8.8"; + + // prepare a container with custom DNS + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withDns(dnsServer) + .withCmd("true").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(isEmptyString())); + + // start container _without_any_customization_ (important!) + dockerClient.startContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + + // The DNS setting survived. + assertThat(inspectContainerResponse.getHostConfig().getDns(), is(notNullValue())); + assertThat(Arrays.asList(inspectContainerResponse.getHostConfig().getDns()), contains(dnsServer)); + } + + @Test + public void anUnconfiguredCommandSerializesToEmptyJson() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + StartContainerCmd command = dockerClient.startContainerCmd(""); + assertThat(objectMapper.writeValueAsString(command), is("{}")); + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/StatsCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/StatsCmdExecTest.java new file mode 100644 index 000000000..2b84ae6b0 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/StatsCmdExecTest.java @@ -0,0 +1,106 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.SecureRandom; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.model.Statistics; +import com.github.dockerjava.core.async.ResultCallbackTemplate; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class StatsCmdExecTest extends AbstractNettyDockerClientTest { + + private static int NUM_STATS = 5; + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void testStatsStreaming() throws InterruptedException, IOException { + TimeUnit.SECONDS.sleep(1); + + CountDownLatch countDownLatch = new CountDownLatch(NUM_STATS); + + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("top") + .withName(containerName).exec(); + LOG.info("Created container {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + StatsCallbackTest statsCallback = dockerClient.statsCmd(container.getId()) + .exec(new StatsCallbackTest(countDownLatch)); + + countDownLatch.await(3, TimeUnit.SECONDS); + Boolean gotStats = statsCallback.gotStats(); + + LOG.info("Stop stats collection"); + + statsCallback.close(); + + LOG.info("Stopping container"); + dockerClient.stopContainerCmd(container.getId()).exec(); + dockerClient.removeContainerCmd(container.getId()).exec(); + + LOG.info("Completed test"); + assertTrue(gotStats, "Expected true"); + + } + + private class StatsCallbackTest extends ResultCallbackTemplate { + private final CountDownLatch countDownLatch; + + private Boolean gotStats = false; + + public StatsCallbackTest(CountDownLatch countDownLatch) { + this.countDownLatch = countDownLatch; + } + + @Override + public void onNext(Statistics stats) { + LOG.info("Received stats #{}: {}", countDownLatch.getCount(), stats); + if (stats != null) { + gotStats = true; + } + countDownLatch.countDown(); + } + + public Boolean gotStats() { + return gotStats; + } + } +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/StopContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/StopContainerCmdExecTest.java new file mode 100644 index 000000000..01bf74458 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/StopContainerCmdExecTest.java @@ -0,0 +1,79 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class StopContainerCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(StopContainerCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test(groups = "ignoreInCircleCi") + public void testStopContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999").exec(); + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + dockerClient.startContainerCmd(container.getId()).exec(); + + LOG.info("Stopping container: {}", container.getId()); + dockerClient.stopContainerCmd(container.getId()).withTimeout(2).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + assertThat(inspectContainerResponse.getState().getRunning(), is(equalTo(false))); + assertThat(inspectContainerResponse.getState().getExitCode(), not(equalTo(0))); + } + + @Test + public void testStopNonExistingContainer() throws DockerException { + try { + dockerClient.stopContainerCmd("non-existing").withTimeout(2).exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/TagImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/TagImageCmdExecTest.java new file mode 100644 index 000000000..bbab169ef --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/TagImageCmdExecTest.java @@ -0,0 +1,63 @@ +package com.github.dockerjava.netty.exec; + +import java.lang.reflect.Method; + +import org.apache.commons.lang.math.RandomUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class TagImageCmdExecTest extends AbstractNettyDockerClientTest { + + public static final Logger LOG = LoggerFactory.getLogger(TagImageCmdExecTest.class); + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void tagImage() throws Exception { + String tag = "" + RandomUtils.nextInt(Integer.MAX_VALUE); + + dockerClient.tagImageCmd("busybox:latest", "docker-java/busybox", tag).exec(); + + dockerClient.removeImageCmd("docker-java/busybox:" + tag).exec(); + } + + @Test + public void tagNonExistingImage() throws Exception { + String tag = "" + RandomUtils.nextInt(Integer.MAX_VALUE); + + try { + dockerClient.tagImageCmd("non-existing", "docker-java/busybox", tag).exec(); + fail("expected NotFoundException"); + } catch (NotFoundException e) { + } + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/VersionCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/VersionCmdExecTest.java new file mode 100644 index 000000000..7709fa56d --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/VersionCmdExecTest.java @@ -0,0 +1,52 @@ +package com.github.dockerjava.netty.exec; + +import java.lang.reflect.Method; + +import org.apache.commons.lang.StringUtils; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.Version; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class VersionCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void version() throws DockerException { + Version version = dockerClient.versionCmd().exec(); + LOG.info(version.toString()); + + assertTrue(version.getGoVersion().length() > 0); + assertTrue(version.getVersion().length() > 0); + + assertEquals(StringUtils.split(version.getVersion(), ".").length, 3); + + } + +} diff --git a/src/test/java/com/github/dockerjava/netty/exec/WaitContainerCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/WaitContainerCmdExecTest.java new file mode 100644 index 000000000..527d5f995 --- /dev/null +++ b/src/test/java/com/github/dockerjava/netty/exec/WaitContainerCmdExecTest.java @@ -0,0 +1,110 @@ +package com.github.dockerjava.netty.exec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +import java.lang.reflect.Method; + +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.WaitResponse; +import com.github.dockerjava.core.command.WaitContainerResultCallback; +import com.github.dockerjava.netty.AbstractNettyDockerClientTest; + +@Test(groups = "integration") +public class WaitContainerCmdExecTest extends AbstractNettyDockerClientTest { + + @BeforeTest + public void beforeTest() throws Exception { + super.beforeTest(); + } + + @AfterTest + public void afterTest() { + super.afterTest(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + super.beforeMethod(method); + } + + @AfterMethod + public void afterMethod(ITestResult result) { + super.afterMethod(result); + } + + @Test + public void testWaitContainer() throws DockerException { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true").exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()) + .awaitStatusCode(); + LOG.info("Container exit code: {}", exitCode); + + assertThat(exitCode, equalTo(0)); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + assertThat(inspectContainerResponse.getState().getRunning(), is(equalTo(false))); + assertThat(inspectContainerResponse.getState().getExitCode(), is(equalTo(exitCode))); + } + + @Test(expectedExceptions = NotFoundException.class) + public void testWaitNonExistingContainer() throws DockerException { + + WaitContainerResultCallback callback = new WaitContainerResultCallback() { + public void onNext(WaitResponse waitResponse) { + fail("expected NotFoundException"); + }; + }; + + dockerClient.waitContainerCmd("non-existing").exec(callback).awaitStatusCode(); + } + + @Test + public void testWaitContainerAbort() throws Exception { + + CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999").exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(isEmptyString())); + + dockerClient.startContainerCmd(container.getId()).exec(); + + WaitContainerResultCallback callback = dockerClient.waitContainerCmd(container.getId()).exec( + new WaitContainerResultCallback()); + + Thread.sleep(5000); + + System.err.println("closing callback"); + + callback.close(); + + dockerClient.killContainerCmd(container.getId()).exec(); + + InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); + LOG.info("Container Inspect: {}", inspectContainerResponse.toString()); + + assertThat(inspectContainerResponse.getState().getRunning(), is(equalTo(false))); + } +} diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml index c2d4557a4..b4309b868 100644 --- a/src/test/resources/logback.xml +++ b/src/test/resources/logback.xml @@ -8,6 +8,7 @@ +