diff --git a/src/main/java/com/spotify/docker/client/messages/HostConfig.java b/src/main/java/com/spotify/docker/client/messages/HostConfig.java old mode 100755 new mode 100644 index d9a4c61d7..e0baddeb7 --- a/src/main/java/com/spotify/docker/client/messages/HostConfig.java +++ b/src/main/java/com/spotify/docker/client/messages/HostConfig.java @@ -106,6 +106,8 @@ public class HostConfig { private Integer pidsLimit; @JsonProperty("Tmpfs") private ImmutableMap tmpfs; + @JsonProperty("ReadonlyRootfs") + private Boolean readonlyRootfs; private HostConfig() { } @@ -145,6 +147,7 @@ private HostConfig(final Builder builder) { this.autoRemove = builder.autoRemove; this.pidsLimit = builder.pidsLimit; this.tmpfs = builder.tmpfs; + this.readonlyRootfs = builder.readonlyRootfs; } public List binds() { @@ -279,6 +282,10 @@ public ImmutableMap tmpfs() { return tmpfs; } + public Boolean readonlyRootfs() { + return readonlyRootfs; + } + public Boolean autoRemove() { return autoRemove; } @@ -325,7 +332,8 @@ public boolean equals(final Object o) { Objects.equals(this.oomScoreAdj, that.oomScoreAdj) && Objects.equals(this.autoRemove, that.autoRemove) && Objects.equals(this.pidsLimit, that.pidsLimit) && - Objects.equals(this.tmpfs, that.tmpfs); + Objects.equals(this.tmpfs, that.tmpfs) && + Objects.equals(this.readonlyRootfs, that.readonlyRootfs); } @Override @@ -335,7 +343,7 @@ public int hashCode() { capDrop, networkMode, securityOpt, devices, memory, memorySwap, memoryReservation, cpuShares, cpusetCpus, cpuQuota, cgroupParent, restartPolicy, logConfig, ipcMode, ulimits, pidMode, shmSize, - oomKillDisable, oomScoreAdj, autoRemove, pidsLimit, tmpfs); + oomKillDisable, oomScoreAdj, autoRemove, pidsLimit, tmpfs, readonlyRootfs); } @Override @@ -375,6 +383,7 @@ public String toString() { .add("autoRemove", autoRemove) .add("pidsLimit", pidsLimit) .add("tmpfs", tmpfs) + .add("readonlyRootfs", readonlyRootfs) .toString(); } @@ -536,6 +545,7 @@ public static class Builder { private Boolean autoRemove; private Integer pidsLimit; private ImmutableMap tmpfs; + private Boolean readonlyRootfs; private Builder() { } @@ -575,6 +585,7 @@ private Builder(final HostConfig hostConfig) { this.autoRemove = hostConfig.autoRemove; this.pidsLimit = hostConfig.pidsLimit; this.tmpfs = hostConfig.tmpfs; + this.readonlyRootfs = hostConfig.readonlyRootfs; } /** @@ -1098,7 +1109,12 @@ public Builder pidsLimit(final Integer pidsLimit) { } public Integer pidsLimit() { - return pidsLimit; + return pidsLimit; + } + + public Builder readonlyRootfs(final Boolean readonlyRootfs) { + this.readonlyRootfs = readonlyRootfs; + return this; } public Builder tmpfs(final ImmutableMap tmpfs) { @@ -1110,6 +1126,10 @@ public ImmutableMap tmpfs() { return tmpfs; } + public Boolean readonlyRootfs() { + return readonlyRootfs; + } + public HostConfig build() { return new HostConfig(this); } diff --git a/src/test/java/com/spotify/docker/client/DefaultDockerClientTest.java b/src/test/java/com/spotify/docker/client/DefaultDockerClientTest.java index 6b428fc2f..a73a8e87d 100755 --- a/src/test/java/com/spotify/docker/client/DefaultDockerClientTest.java +++ b/src/test/java/com/spotify/docker/client/DefaultDockerClientTest.java @@ -18,23 +18,72 @@ package com.spotify.docker.client; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.util.StdDateFormat; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.base.Throwables; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.common.io.Resources; -import com.google.common.util.concurrent.SettableFuture; +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Strings.isNullOrEmpty; +import static com.google.common.collect.Iterables.getOnlyElement; +import static com.spotify.docker.client.DefaultDockerClient.NO_TIMEOUT; +import static com.spotify.docker.client.DockerClient.ListContainersParam.allContainers; +import static com.spotify.docker.client.DockerClient.ListContainersParam.withLabel; +import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusCreated; +import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusExited; +import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusPaused; +import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusRunning; +import static com.spotify.docker.client.DockerClient.ListImagesParam.allImages; +import static com.spotify.docker.client.DockerClient.ListImagesParam.byName; +import static com.spotify.docker.client.DockerClient.ListImagesParam.danglingImages; +import static com.spotify.docker.client.DockerClient.ListImagesParam.digests; +import static com.spotify.docker.client.DockerClient.ListVolumesParam.dangling; +import static com.spotify.docker.client.DockerClient.ListVolumesParam.driver; +import static com.spotify.docker.client.DockerClient.ListVolumesParam.name; +import static com.spotify.docker.client.DockerClient.LogsParam.follow; +import static com.spotify.docker.client.DockerClient.LogsParam.since; +import static com.spotify.docker.client.DockerClient.LogsParam.stderr; +import static com.spotify.docker.client.DockerClient.LogsParam.stdout; +import static com.spotify.docker.client.DockerClient.LogsParam.tail; +import static com.spotify.docker.client.DockerClient.LogsParam.timestamps; +import static com.spotify.docker.client.VersionCompare.compareVersion; +import static com.spotify.docker.client.messages.RemovedImage.Type.UNTAGGED; +import static java.lang.Long.toHexString; +import static java.lang.String.format; +import static java.lang.System.getenv; +import static org.apache.commons.lang.StringUtils.containsIgnoreCase; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.any; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.either; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.isIn; +import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.collection.IsEmptyCollection.empty; +import static org.hamcrest.collection.IsMapContaining.hasEntry; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeThat; +import static org.junit.Assume.assumeTrue; import com.spotify.docker.client.DockerClient.AttachParameter; import com.spotify.docker.client.DockerClient.BuildParam; @@ -101,6 +150,23 @@ import com.spotify.docker.client.messages.swarm.Task; import com.spotify.docker.client.messages.swarm.TaskSpec; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.util.StdDateFormat; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Throwables; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.io.Resources; +import com.google.common.util.concurrent.SettableFuture; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; @@ -158,73 +224,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; -import static com.google.common.base.Charsets.UTF_8; -import static com.google.common.base.Strings.isNullOrEmpty; -import static com.google.common.collect.Iterables.getOnlyElement; -import static com.spotify.docker.client.DefaultDockerClient.NO_TIMEOUT; -import static com.spotify.docker.client.DockerClient.ListContainersParam.allContainers; -import static com.spotify.docker.client.DockerClient.ListContainersParam.withLabel; -import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusCreated; -import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusExited; -import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusPaused; -import static com.spotify.docker.client.DockerClient.ListContainersParam.withStatusRunning; -import static com.spotify.docker.client.DockerClient.ListImagesParam.allImages; -import static com.spotify.docker.client.DockerClient.ListImagesParam.byName; -import static com.spotify.docker.client.DockerClient.ListImagesParam.danglingImages; -import static com.spotify.docker.client.DockerClient.ListImagesParam.digests; -import static com.spotify.docker.client.DockerClient.ListVolumesParam.dangling; -import static com.spotify.docker.client.DockerClient.ListVolumesParam.driver; -import static com.spotify.docker.client.DockerClient.ListVolumesParam.name; -import static com.spotify.docker.client.DockerClient.LogsParam.follow; -import static com.spotify.docker.client.DockerClient.LogsParam.since; -import static com.spotify.docker.client.DockerClient.LogsParam.stderr; -import static com.spotify.docker.client.DockerClient.LogsParam.stdout; -import static com.spotify.docker.client.DockerClient.LogsParam.tail; -import static com.spotify.docker.client.DockerClient.LogsParam.timestamps; -import static com.spotify.docker.client.VersionCompare.compareVersion; -import static com.spotify.docker.client.messages.RemovedImage.Type.UNTAGGED; -import static java.lang.Long.toHexString; -import static java.lang.String.format; -import static java.lang.System.getenv; -import static org.apache.commons.lang.StringUtils.containsIgnoreCase; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.any; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.both; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isEmptyOrNullString; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.lessThan; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.startsWith; -import static org.hamcrest.collection.IsEmptyCollection.empty; -import static org.hamcrest.collection.IsMapContaining.hasEntry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeThat; -import static org.junit.Assume.assumeTrue; - public class DefaultDockerClientTest { private static final String BUSYBOX = "busybox"; @@ -3404,6 +3403,24 @@ public void testTmpfs() throws Exception { assertThat(info.hostConfig().tmpfs(), is(tmpfs)); } + @Test + public void testReadonlyRootfs() throws Exception { + // Pull image + sut.pull(BUSYBOX_LATEST); + + final ContainerConfig config = ContainerConfig.builder() + .image(BUSYBOX_LATEST) + .hostConfig(HostConfig.builder() + .readonlyRootfs(true) // Defaults to -1 + .build()) + .build(); + + final ContainerCreation container = sut.createContainer(config, randomName()); + final ContainerInfo info = sut.inspectContainer(container.id()); + + assertThat(info.hostConfig().readonlyRootfs(), is(true)); + } + @Test(expected = ContainerNotFoundException.class) public void testAutoRemoveWhenSetToTrue() throws Exception { requireDockerApiVersionAtLeast("1.25", "AutoRemove");