Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions src/main/java/com/github/dockerjava/api/model/Bind.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public class Bind implements Serializable {

private AccessMode accessMode;

/**
* @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_23}
*/
private Boolean noCopy;

/**
* @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_17}
*/
Expand All @@ -27,15 +32,24 @@ public Bind(String path, Volume volume) {
this(path, volume, AccessMode.DEFAULT, SELContext.DEFAULT);
}

public Bind(String path, Volume volume, Boolean noCopy) {
this(path, volume, AccessMode.DEFAULT, SELContext.DEFAULT, noCopy);
}

public Bind(String path, Volume volume, AccessMode accessMode) {
this(path, volume, accessMode, SELContext.DEFAULT);
}

public Bind(String path, Volume volume, AccessMode accessMode, SELContext secMode) {
this(path, volume, accessMode, secMode, null);
}

public Bind(String path, Volume volume, AccessMode accessMode, SELContext secMode, Boolean noCopy) {
this.path = path;
this.volume = volume;
this.accessMode = accessMode;
this.secMode = secMode;
this.noCopy = noCopy;
}

public String getPath() {
Expand All @@ -54,6 +68,10 @@ public SELContext getSecMode() {
return secMode;
}

public Boolean getNoCopy() {
return noCopy;
}

/**
* Parses a bind mount specification to a {@link Bind}.
*
Expand All @@ -74,15 +92,18 @@ public static Bind parse(String serialized) {
String[] flags = parts[2].split(",");
AccessMode accessMode = AccessMode.DEFAULT;
SELContext seMode = SELContext.DEFAULT;
Boolean nocopy = null;
for (String p : flags) {
if (p.length() == 2) {
accessMode = AccessMode.valueOf(p.toLowerCase());
} else if ("nocopy".equals(p)) {
nocopy = true;
} else {
seMode = SELContext.fromString(p);
}
}

return new Bind(parts[0], new Volume(parts[1]), accessMode, seMode);
return new Bind(parts[0], new Volume(parts[1]), accessMode, seMode, nocopy);
}
default: {
throw new IllegalArgumentException();
Expand All @@ -102,6 +123,7 @@ public boolean equals(Object obj) {
.append(volume, other.getVolume())
.append(accessMode, other.getAccessMode())
.append(secMode, other.getSecMode())
.append(noCopy, other.getNoCopy())
.isEquals();
} else {
return super.equals(obj);
Expand All @@ -115,6 +137,7 @@ public int hashCode() {
.append(volume)
.append(accessMode)
.append(secMode)
.append(noCopy)
.toHashCode();
}

Expand All @@ -127,10 +150,11 @@ public int hashCode() {
*/
@Override
public String toString() {
return String.format("%s:%s:%s%s",
return String.format("%s:%s:%s%s%s",
path,
volume.getPath(),
accessMode.toString(),
secMode != SELContext.none ? "," + secMode.toString() : "");
secMode != SELContext.none ? "," + secMode.toString() : "",
noCopy != null ? ",nocopy" : "");
}
}
23 changes: 23 additions & 0 deletions src/test/java/com/github/dockerjava/api/model/BindTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.github.dockerjava.api.model.AccessMode.ro;
import static com.github.dockerjava.api.model.AccessMode.rw;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;

import org.testng.annotations.Test;
Expand All @@ -16,6 +17,7 @@ public void parseUsingDefaultAccessMode() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(AccessMode.DEFAULT));
assertThat(bind.getSecMode(), is(SELContext.none));
assertThat(bind.getNoCopy(), nullValue());
}

@Test
Expand All @@ -25,6 +27,17 @@ public void parseReadWrite() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(rw));
assertThat(bind.getSecMode(), is(SELContext.none));
assertThat(bind.getNoCopy(), nullValue());
}

@Test
public void parseReadWriteNoCopy() {
Bind bind = Bind.parse("/host:/container:rw,nocopy");
assertThat(bind.getPath(), is("/host"));
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(rw));
assertThat(bind.getSecMode(), is(SELContext.none));
assertThat(bind.getNoCopy(), is(true));
}

@Test
Expand All @@ -34,6 +47,7 @@ public void parseReadOnly() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(ro));
assertThat(bind.getSecMode(), is(SELContext.none));
assertThat(bind.getNoCopy(), nullValue());
}

@Test
Expand All @@ -43,12 +57,14 @@ public void parseSELOnly() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(AccessMode.DEFAULT));
assertThat(bind.getSecMode(), is(SELContext.single));
assertThat(bind.getNoCopy(), nullValue());

bind = Bind.parse("/host:/container:z");
assertThat(bind.getPath(), is("/host"));
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(AccessMode.DEFAULT));
assertThat(bind.getSecMode(), is(SELContext.shared));
assertThat(bind.getNoCopy(), nullValue());
}

@Test
Expand All @@ -58,6 +74,7 @@ public void parseReadWriteSEL() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(rw));
assertThat(bind.getSecMode(), is(SELContext.single));
assertThat(bind.getNoCopy(), nullValue());
}

@Test
Expand All @@ -67,6 +84,7 @@ public void parseReadOnlySEL() {
assertThat(bind.getVolume().getPath(), is("/container"));
assertThat(bind.getAccessMode(), is(ro));
assertThat(bind.getSecMode(), is(SELContext.shared));
assertThat(bind.getNoCopy(), nullValue());
}

@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing Bind.*")
Expand All @@ -93,6 +111,11 @@ public void toStringReadOnly() {
public void toStringReadWrite() {
assertThat(Bind.parse("/host:/container:rw").toString(), is("/host:/container:rw"));
}

@Test
public void toStringReadWriteNoCopy() {
assertThat(Bind.parse("/host:/container:rw,nocopy").toString(), is("/host:/container:rw,nocopy"));
}

@Test
public void toStringDefaultAccessMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.CreateNetworkResponse;
import com.github.dockerjava.api.command.CreateVolumeResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.exception.ConflictException;
import com.github.dockerjava.api.exception.DockerException;
Expand All @@ -15,6 +16,7 @@
import com.github.dockerjava.api.model.Network;
import com.github.dockerjava.api.model.Ports;
import com.github.dockerjava.api.model.Ports.Binding;
import com.github.dockerjava.core.RemoteApiVersion;
import com.github.dockerjava.api.model.RestartPolicy;
import com.github.dockerjava.api.model.Ulimit;
import com.github.dockerjava.api.model.Volume;
Expand All @@ -23,6 +25,7 @@

import org.apache.commons.io.FileUtils;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
Expand All @@ -40,6 +43,7 @@

import static com.github.dockerjava.api.model.Capability.MKNOD;
import static com.github.dockerjava.api.model.Capability.NET_ADMIN;
import static com.github.dockerjava.utils.TestUtils.getVersion;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
Expand Down Expand Up @@ -138,6 +142,39 @@ public void createContainerWithReadOnlyVolume() throws DockerException {
// assertFalse(inspectContainerResponse.getMounts().get(0).getRW());
}

@Test
public void createContainerWithNoCopyVolumes() throws DockerException {
final RemoteApiVersion apiVersion = getVersion(dockerClient);

if (!apiVersion.isGreaterOrEqual(RemoteApiVersion.VERSION_1_23)) {
throw new SkipException("API version should be >= 1.23");
}

Volume volume1 = new Volume("/opt/webapp1");
String container1Name = UUID.randomUUID().toString();

CreateVolumeResponse volumeResponse = dockerClient.createVolumeCmd().withName("webapp1").exec();
assertThat(volumeResponse.getName(), equalTo("webapp1"));
assertThat(volumeResponse.getDriver(), equalTo("local"));
assertThat(volumeResponse.getMountpoint(), containsString("/webapp1/"));

Bind bind1 = new Bind("webapp1", volume1, true);

CreateContainerResponse container1 = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999")
.withName(container1Name)
.withBinds(bind1).exec();
LOG.info("Created container1 {}", container1.toString());

InspectContainerResponse inspectContainerResponse1 = dockerClient.inspectContainerCmd(container1.getId()).exec();

assertThat(Arrays.asList(inspectContainerResponse1.getHostConfig().getBinds()), contains(bind1));
assertThat(inspectContainerResponse1, mountedVolumes(contains(volume1)));

assertThat(inspectContainerResponse1.getMounts().get(0).getDestination(), equalTo(volume1));
assertThat(inspectContainerResponse1.getMounts().get(0).getMode(), equalTo("rw,nocopy"));
assertThat(inspectContainerResponse1.getMounts().get(0).getRW(), equalTo(true));
}

@Test
public void createContainerWithVolumesFrom() throws DockerException {

Expand Down