diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java index 3857f2fa2..59c90aa0b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java @@ -54,6 +54,8 @@ import com.github.dockerjava.api.command.RemoveServiceCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -165,6 +167,8 @@ public interface DockerClient extends Closeable { ExecCreateCmd execCreateCmd(@Nonnull String containerId); + ResizeExecCmd resizeExecCmd(@Nonnull String execId); + InspectContainerCmd inspectContainerCmd(@Nonnull String containerId); RemoveContainerCmd removeContainerCmd(@Nonnull String containerId); @@ -242,6 +246,8 @@ public interface DockerClient extends Closeable { RestartContainerCmd restartContainerCmd(@Nonnull String containerId); + ResizeContainerCmd resizeContainerCmd(@Nonnull String containerId); + CommitCmd commitCmd(@Nonnull String containerId); BuildImageCmd buildImageCmd(); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java index dbd691974..c414a6d21 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java @@ -25,11 +25,21 @@ public PingCmd.Exec createPingCmdExec() { return getDockerCmdExecFactory().createPingCmdExec(); } + @Override + public ResizeContainerCmd.Exec createResizeContainerCmdExec() { + return getDockerCmdExecFactory().createResizeContainerCmdExec(); + } + @Override public ExecCreateCmd.Exec createExecCmdExec() { return getDockerCmdExecFactory().createExecCmdExec(); } + @Override + public ResizeExecCmd.Exec createResizeExecCmdExec() { + return getDockerCmdExecFactory().createResizeExecCmdExec(); + } + @Override public VersionCmd.Exec createVersionCmdExec() { return getDockerCmdExecFactory().createVersionCmdExec(); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java index e01d9239f..27084bf76 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java @@ -49,8 +49,12 @@ public interface DockerCmdExecFactory extends Closeable { AttachContainerCmd.Exec createAttachContainerCmdExec(); + ResizeContainerCmd.Exec createResizeContainerCmdExec(); + ExecStartCmd.Exec createExecStartCmdExec(); + ResizeExecCmd.Exec createResizeExecCmdExec(); + InspectExecCmd.Exec createInspectExecCmdExec(); LogContainerCmd.Exec createLogContainerCmdExec(); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java new file mode 100644 index 000000000..fef0087ed --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +public interface ResizeContainerCmd extends SyncDockerCmd { + + @CheckForNull + String getContainerId(); + + Integer getHeight(); + + Integer getWidth(); + + ResizeContainerCmd withContainerId(@Nonnull String execId); + + ResizeContainerCmd withSize(int height, int width); + + /** + * @throws NotFoundException no such container instance + */ + @Override + Void exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java new file mode 100644 index 000000000..5910705e0 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java @@ -0,0 +1,29 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +public interface ResizeExecCmd extends SyncDockerCmd { + @CheckForNull + String getExecId(); + + Integer getHeight(); + + Integer getWidth(); + + ResizeExecCmd withExecId(@Nonnull String execId); + + ResizeExecCmd withSize(int height, int width); + + /** + * @throws NotFoundException no such exec instance + */ + @Override + Void exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java b/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java index e93260b8a..e31431741 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java @@ -57,6 +57,8 @@ import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -92,6 +94,8 @@ import com.github.dockerjava.core.exec.EventsCmdExec; import com.github.dockerjava.core.exec.ExecCreateCmdExec; import com.github.dockerjava.core.exec.ExecStartCmdExec; +import com.github.dockerjava.core.exec.ResizeContainerCmdExec; +import com.github.dockerjava.core.exec.ResizeExecCmdExec; import com.github.dockerjava.core.exec.InfoCmdExec; import com.github.dockerjava.core.exec.InitializeSwarmCmdExec; import com.github.dockerjava.core.exec.InspectContainerCmdExec; @@ -303,11 +307,21 @@ public AttachContainerCmd.Exec createAttachContainerCmdExec() { return new AttachContainerCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ResizeContainerCmd.Exec createResizeContainerCmdExec() { + return new ResizeContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public ExecStartCmd.Exec createExecStartCmdExec() { return new ExecStartCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ResizeExecCmd.Exec createResizeExecCmdExec() { + return new ResizeExecCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public InspectExecCmd.Exec createInspectExecCmdExec() { return new InspectExecCmdExec(getBaseResource(), getDockerClientConfig()); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java index 4caae102c..eddddc220 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java @@ -56,6 +56,8 @@ import com.github.dockerjava.api.command.RemoveServiceCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -132,6 +134,8 @@ import com.github.dockerjava.core.command.RemoveServiceCmdImpl; import com.github.dockerjava.core.command.RemoveVolumeCmdImpl; import com.github.dockerjava.core.command.RenameContainerCmdImpl; +import com.github.dockerjava.core.command.ResizeContainerCmdImpl; +import com.github.dockerjava.core.command.ResizeExecCmdImpl; import com.github.dockerjava.core.command.RestartContainerCmdImpl; import com.github.dockerjava.core.command.SaveImageCmdImpl; import com.github.dockerjava.core.command.SaveImagesCmdImpl; @@ -386,6 +390,11 @@ public ExecCreateCmd execCreateCmd(String containerId) { return new ExecCreateCmdImpl(getDockerCmdExecFactory().createExecCmdExec(), containerId); } + @Override + public ResizeExecCmd resizeExecCmd(@Nonnull String execId) { + return new ResizeExecCmdImpl(getDockerCmdExecFactory().createResizeExecCmdExec(), execId); + } + @Override public RemoveContainerCmd removeContainerCmd(String containerId) { return new RemoveContainerCmdImpl(getDockerCmdExecFactory().createRemoveContainerCmdExec(), containerId); @@ -464,6 +473,11 @@ public RestartContainerCmd restartContainerCmd(String containerId) { return new RestartContainerCmdImpl(getDockerCmdExecFactory().createRestartContainerCmdExec(), containerId); } + @Override + public ResizeContainerCmd resizeContainerCmd(@Nonnull String containerId) { + return new ResizeContainerCmdImpl(getDockerCmdExecFactory().createResizeContainerCmdExec(), containerId); + } + @Override public CommitCmd commitCmd(String containerId) { return new CommitCmdImpl(getDockerCmdExecFactory().createCommitCmdExec(), containerId); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java new file mode 100644 index 000000000..de1b6ac20 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java @@ -0,0 +1,57 @@ +package com.github.dockerjava.core.command; + +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ResizeContainerCmdImpl extends AbstrDockerCmd implements ResizeContainerCmd { + + private String containerId; + + private Integer height; + + private Integer width; + + public ResizeContainerCmdImpl(ResizeContainerCmd.Exec exec, String execId) { + super(exec); + withContainerId(execId); + } + + @Override + public String getContainerId() { + return containerId; + } + + @Override + public Integer getHeight() { + return height; + } + + @Override + public Integer getWidth() { + return width; + } + + @Override + public ResizeContainerCmd withContainerId(String containerId) { + checkNotNull(containerId, "containerId was not specified"); + this.containerId = containerId; + return this; + } + + @Override + public ResizeContainerCmd withSize(int height, int width) { + this.height = height; + this.width = width; + return this; + } + + /** + * @throws NotFoundException no such exec instance + */ + @Override + public Void exec() throws NotFoundException { + return super.exec(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java new file mode 100644 index 000000000..80b1fef88 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java @@ -0,0 +1,58 @@ +package com.github.dockerjava.core.command; + +import com.github.dockerjava.api.command.ResizeExecCmd; +import com.github.dockerjava.api.exception.NotFoundException; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ResizeExecCmdImpl extends AbstrDockerCmd implements ResizeExecCmd { + + private String execId; + + private Integer height; + + private Integer width; + + public ResizeExecCmdImpl(ResizeExecCmd.Exec exec, String execId) { + super(exec); + withExecId(execId); + } + + @Override + public String getExecId() { + return execId; + } + + @Override + public Integer getHeight() { + return height; + } + + @Override + public Integer getWidth() { + return width; + } + + @Override + public ResizeExecCmd withExecId(String execId) { + checkNotNull(execId, "execId was not specified"); + this.execId = execId; + return this; + } + + @Override + public ResizeExecCmd withSize(int height, int width) { + this.height = height; + this.width = width; + return this; + } + + /** + * @throws NotFoundException no such exec instance + */ + @Override + public Void exec() throws NotFoundException { + return super.exec(); + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java new file mode 100644 index 000000000..f13fc582a --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.core.exec; + +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResizeContainerCmdExec extends AbstrSyncDockerCmdExec implements ResizeContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ResizeContainerCmdExec.class); + + public ResizeContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(ResizeContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/resize") + .resolveTemplate("id", command.getContainerId()).queryParam("h", command.getHeight()) + .queryParam("w", command.getWidth()); + + LOGGER.trace("POST: {}", webResource); + + webResource.request().accept(MediaType.APPLICATION_JSON).post(command); + + return null; + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java new file mode 100644 index 000000000..ba01c5ffe --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.core.exec; + +import com.github.dockerjava.api.command.ResizeExecCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class ResizeExecCmdExec extends AbstrSyncDockerCmdExec implements ResizeExecCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ResizeExecCmdExec.class); + + public ResizeExecCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(ResizeExecCmd command) { + WebTarget webResource = getBaseResource().path("/exec/{id}/resize") + .resolveTemplate("id", command.getExecId()).queryParam("h", command.getHeight()).queryParam("w", command.getWidth()); + + LOGGER.trace("POST: {}", webResource); + + webResource.request().accept(MediaType.APPLICATION_JSON).post(null); + + return null; + } + +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java new file mode 100644 index 000000000..eeb79b2ff --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java @@ -0,0 +1,39 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class ResizeContainerCmdIT extends CmdIT { + private static final Logger LOG = LoggerFactory.getLogger(ResizeContainerCmdIT.class); + + private static final int TTY_HEIGHT = 30; + private static final int TTY_WIDTH = 120; + + @Test + public void resizeContainerTtyTest() { + String containerName = "generated_" + new SecureRandom().nextInt(); + + // wait until tty size changed to target size + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withUser("root") + .withCmd("sh", "-c", String.format("until stty size | grep '%d %d'; do : ; done", TTY_HEIGHT, TTY_WIDTH)) + .withName(containerName).withTty(true).withStdinOpen(true).exec(); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + dockerRule.getClient().resizeContainerCmd(container.getId()).withSize(TTY_HEIGHT, TTY_WIDTH).exec(); + + int exitCode = dockerRule.getClient().waitContainerCmd(container.getId()).start() + .awaitStatusCode(10, TimeUnit.SECONDS); + + LOG.info("Container exit code: {}", exitCode); + + assertThat(exitCode, equalTo(0)); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java new file mode 100644 index 000000000..9e5c9b65f --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java @@ -0,0 +1,48 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + + +public class ResizeExecCmdIT extends CmdIT { + private static final Logger LOG = LoggerFactory.getLogger(ResizeExecCmdIT.class); + + private static final int TTY_HEIGHT = 30; + private static final int TTY_WIDTH = 120; + + @Test + public void resizeExecInstanceTtyTest() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withUser("root") + .withCmd("sleep", "9999").withName(containerName).exec(); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + // wait until tty size changed to target size + ExecCreateCmdResponse execCreateCmdResponse = dockerRule.getClient().execCreateCmd(container.getId()).withTty(true) + .withAttachStdout(true).withAttachStderr(true) + .withCmd("sh", "-c", String.format("until stty size | grep '%d %d'; do : ; done", TTY_HEIGHT, TTY_WIDTH)).exec(); + + final ExecStartResultCallback execStartResultCallback = new ExecStartResultCallback(System.out, System.err); + + dockerRule.getClient().execStartCmd(execCreateCmdResponse.getId()).exec(execStartResultCallback).awaitStarted(); + + dockerRule.getClient().resizeExecCmd(execCreateCmdResponse.getId()).withSize(TTY_HEIGHT, TTY_WIDTH).exec(); + + // time out, exec instance resize failed + boolean waitResult = execStartResultCallback.awaitCompletion(10, TimeUnit.SECONDS); + + assertThat(waitResult, equalTo(true)); + } +}