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 d289d35be..cb14b7e5b 100644 --- a/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java +++ b/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java @@ -4,6 +4,7 @@ import java.util.Map; import com.github.dockerjava.core.RemoteApiVersion; + import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; @@ -14,6 +15,7 @@ import com.github.dockerjava.api.model.ContainerConfig; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.VolumeBind; import com.github.dockerjava.api.model.VolumeBinds; import com.github.dockerjava.api.model.VolumeRW; @@ -89,6 +91,9 @@ public class InspectContainerResponse { @JsonProperty("VolumesRW") private VolumesRW volumesRW; + @JsonProperty("Mounts") + private List mounts; + public String getId() { return id; } @@ -134,7 +139,13 @@ public VolumeBind[] getVolumes() { return volumes == null ? null : volumes.getBinds(); } + /** + * @deprecated As of {@link RemoteApiVersion#VERSION_1_20} + * use {@link #getMounts()} instead + */ @JsonIgnore + @Deprecated + @CheckForNull public VolumeRW[] getVolumesRW() { return volumesRW == null ? null : volumesRW.getVolumesRW(); } @@ -167,6 +178,14 @@ public String getMountLabel() { return mountLabel; } + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + public List getMounts() { + return mounts; + } + public List getExecIds() { return execIds; } @@ -413,4 +432,81 @@ public String toString() { } } + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Mount { + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("Name") + private String name; + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("Source") + private String source; + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("Destination") + private Volume destination; + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("Driver") + private String driver; + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("Mode") + private String mode; + + /** + * @since {@link RemoteApiVersion#VERSION_1_20} + */ + @CheckForNull + @JsonProperty("RW") + private Boolean rw; + + @CheckForNull + public String getName() { + return name; + } + + @CheckForNull + public String getSource() { + return source; + } + + @CheckForNull + public Volume getDestination() { + return destination; + } + + @CheckForNull + public String getDriver() { + return driver; + } + + @CheckForNull + public String getMode() { + return mode; + } + + @CheckForNull + public Boolean getRW() { + return rw; + } + + } + } diff --git a/src/main/java/com/github/dockerjava/api/model/Binds.java b/src/main/java/com/github/dockerjava/api/model/Binds.java index 1824ca77b..917cfdcbd 100644 --- a/src/main/java/com/github/dockerjava/api/model/Binds.java +++ b/src/main/java/com/github/dockerjava/api/model/Binds.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -17,7 +16,6 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.node.NullNode; @JsonSerialize(using = Binds.Serializer.class) @JsonDeserialize(using = Binds.Deserializer.class) @@ -58,12 +56,11 @@ public Binds deserialize(JsonParser jsonParser, DeserializationContext deseriali List binds = new ArrayList(); ObjectCodec oc = jsonParser.getCodec(); JsonNode node = oc.readTree(jsonParser); - for (Iterator> it = node.fields(); it.hasNext();) { + for (Iterator it = node.elements(); it.hasNext();) { + + JsonNode field = it.next(); + binds.add(Bind.parse(field.asText())); - Map.Entry field = it.next(); - if (!field.getValue().equals(NullNode.getInstance())) { - binds.add(Bind.parse(field.getKey())); - } } return new Binds(binds.toArray(new Bind[0])); } diff --git a/src/main/java/com/github/dockerjava/api/model/VolumeRW.java b/src/main/java/com/github/dockerjava/api/model/VolumeRW.java index 46d4539b4..bdb347bee 100644 --- a/src/main/java/com/github/dockerjava/api/model/VolumeRW.java +++ b/src/main/java/com/github/dockerjava/api/model/VolumeRW.java @@ -18,14 +18,17 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.node.NullNode; +import com.github.dockerjava.core.RemoteApiVersion; /** * Represents a bind mounted volume in a Docker container. * * @see Bind + * @deprecated since {@link RemoteApiVersion#VERSION_1_20} */ @JsonDeserialize(using = VolumeRW.Deserializer.class) @JsonSerialize(using = VolumeRW.Serializer.class) +@Deprecated public class VolumeRW { private Volume volume; diff --git a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java index 2fd228b9f..f2e2489c0 100644 --- a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java +++ b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java @@ -1,7 +1,7 @@ package com.github.dockerjava.client; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import java.io.File; import java.io.IOException; @@ -15,14 +15,17 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.ITestResult; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse.Mount; +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; @@ -32,13 +35,12 @@ import com.github.dockerjava.core.command.BuildImageResultCallback; import com.github.dockerjava.core.command.LogContainerResultCallback; import com.github.dockerjava.core.command.PullImageResultCallback; -import com.google.common.base.Joiner; public abstract class AbstractDockerClientTest extends Assert { public static final Logger LOG = LoggerFactory.getLogger(AbstractDockerClientTest.class); - private String apiVersion = "1.19"; + private String apiVersion = "1.21"; protected DockerClient dockerClient; @@ -172,21 +174,23 @@ public static Boolean available(int port) { return false; } - /** - * Asserts that {@link InspectContainerResponse#getVolumes()} (.Volumes) has {@link VolumeBind}s for - * the given {@link Volume}s - */ - public static void assertContainerHasVolumes(InspectContainerResponse inspectContainerResponse, - Volume... expectedVolumes) { - - List volumes = new ArrayList(); - VolumeBind[] volumeBinds = inspectContainerResponse.getVolumes(); - if (volumeBinds != null) { - for (VolumeBind bind : volumeBinds) { - volumes.add(new Volume(bind.getContainerPath())); + protected MountedVolumes mountedVolumes(Matcher> subMatcher) { + return new MountedVolumes(subMatcher, "Mounted volumes", "mountedVolumes"); + } + + private static class MountedVolumes extends FeatureMatcher> { + public MountedVolumes(Matcher> subMatcher, String featureDescription, String featureName) { + super(subMatcher, featureDescription, featureName); + } + + @Override + public List featureValueOf(InspectContainerResponse item) { + List volumes = new ArrayList(); + for (Mount mount : item.getMounts()) { + volumes.add(mount.getDestination()); } + return volumes; } - assertThat(volumes, contains(expectedVolumes)); } protected String containerLog(String containerId) throws Exception { diff --git a/src/test/java/com/github/dockerjava/core/command/CreateContainerCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/CreateContainerCmdImplTest.java index f741f5245..4e4cac9f1 100644 --- a/src/test/java/com/github/dockerjava/core/command/CreateContainerCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/CreateContainerCmdImplTest.java @@ -1,29 +1,5 @@ package com.github.dockerjava.core.command; -import com.github.dockerjava.api.exception.ConflictException; -import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.command.InspectContainerResponse; -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.client.AbstractDockerClientTest; -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 static com.github.dockerjava.api.model.Capability.MKNOD; import static com.github.dockerjava.api.model.Capability.NET_ADMIN; import static org.hamcrest.MatcherAssert.assertThat; @@ -45,7 +21,28 @@ import java.util.Map; import java.util.UUID; -import static org.hamcrest.MatcherAssert.assertThat; +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.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.VolumesFrom; +import com.github.dockerjava.client.AbstractDockerClientTest; @Test(groups = "integration") public class CreateContainerCmdImplTest extends AbstractDockerClientTest { @@ -107,9 +104,12 @@ public void createContainerWithVolume() throws DockerException { assertThat(inspectContainerResponse.getConfig().getVolumes().keySet(), contains("/var/log")); - assertThat(inspectContainerResponse.getVolumesRW(), hasItemInArray(new VolumeRW(volume, AccessMode.rw))); + 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 { @@ -128,7 +128,9 @@ public void createContainerWithReadOnlyVolume() throws DockerException { assertThat(inspectContainerResponse.getConfig().getVolumes().keySet(), contains("/srv/test")); - assertThat(Arrays.asList(inspectContainerResponse.getVolumesRW()), contains(new VolumeRW(volume))); + 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 @@ -151,7 +153,7 @@ public void createContainerWithVolumesFrom() throws DockerException { InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) .exec(); - assertContainerHasVolumes(inspectContainerResponse1, volume1, volume2); + assertThat(inspectContainerResponse1, mountedVolumes(containsInAnyOrder(volume1, volume2))); // create a second container with volumes from first container CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") @@ -177,7 +179,8 @@ public void createContainerWithVolumesFrom() throws DockerException { assertThat(inspectContainerResponse2.getHostConfig().getVolumesFrom(), hasItemInArray(new VolumesFrom( container1Name))); - assertContainerHasVolumes(inspectContainerResponse2, volume1, volume2); + + assertThat(inspectContainerResponse2, mountedVolumes(containsInAnyOrder(volume1, volume2))); } @Test diff --git a/src/test/java/com/github/dockerjava/core/command/StartContainerCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/StartContainerCmdImplTest.java index db6e28fe0..b43eb0ff2 100644 --- a/src/test/java/com/github/dockerjava/core/command/StartContainerCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/StartContainerCmdImplTest.java @@ -5,6 +5,7 @@ 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; @@ -24,13 +25,12 @@ import org.testng.annotations.Test; import com.fasterxml.jackson.databind.ObjectMapper; -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.CreateContainerResponse; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.command.StartContainerCmd; -import com.github.dockerjava.api.model.AccessMode; +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.Bind; import com.github.dockerjava.api.model.Device; import com.github.dockerjava.api.model.ExposedPort; @@ -38,7 +38,6 @@ 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.client.AbstractDockerClientTest; @@ -91,11 +90,17 @@ public void startContainerWithVolumes() throws DockerException { inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); - assertContainerHasVolumes(inspectContainerResponse, volume1, volume2); + assertThat(inspectContainerResponse, mountedVolumes(containsInAnyOrder(volume1, volume2))); + + assertThat(inspectContainerResponse.getMounts().size(), equalTo(2)); - assertThat(Arrays.asList(inspectContainerResponse.getVolumesRW()), - contains(new VolumeRW(volume1, AccessMode.ro), new VolumeRW(volume2))); + 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 @@ -117,7 +122,7 @@ public void startContainerWithVolumesFrom() throws DockerException { InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()) .exec(); - assertContainerHasVolumes(inspectContainerResponse1, volume1, volume2); + assertThat(inspectContainerResponse1, mountedVolumes(containsInAnyOrder(volume1, volume2))); CreateContainerResponse container2 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999") .withVolumesFrom(new VolumesFrom(container1Name)).exec(); @@ -129,7 +134,7 @@ public void startContainerWithVolumesFrom() throws DockerException { InspectContainerResponse inspectContainerResponse2 = dockerClient.inspectContainerCmd(container2.getId()) .exec(); - assertContainerHasVolumes(inspectContainerResponse2, volume1, volume2); + assertThat(inspectContainerResponse2, mountedVolumes(containsInAnyOrder(volume1, volume2))); } @Test diff --git a/src/test/resources/testAddUrl/Dockerfile b/src/test/resources/testAddUrl/Dockerfile index ba0b91a0b..d9a0676d4 100644 --- a/src/test/resources/testAddUrl/Dockerfile +++ b/src/test/resources/testAddUrl/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:latest # Copy testrun.sh files into the container -ADD http://www.docker.io /tmp/docker_home.html +ADD https://hub.docker.com/r/marcuslinke/busybox/ /tmp/docker_home.html ADD ./testrun.sh /tmp/ RUN cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh