Skip to content

Commit

Permalink
Support copyUIDGID option in CopyArchiveToContainerCmd (#1963)
Browse files Browse the repository at this point in the history
Fix #1258

Signed-off-by: kwall <[email protected]>
  • Loading branch information
k-wall authored Oct 17, 2022
1 parent 3951333 commit d7db365
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd<Void> {

boolean isDirChildrenOnly();

boolean isCopyUIDGID();
/**
* Set container's id
*
Expand Down Expand Up @@ -49,6 +50,14 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd<Void> {
*/
CopyArchiveToContainerCmd withNoOverwriteDirNonDir(boolean noOverwriteDirNonDir);

/**
* If set to true then ownership is set to the user and primary group at the destination
*
* @param copyUIDGID
* flag to know if ownership should be set to the user and primary group at the destination
*/
CopyArchiveToContainerCmd withCopyUIDGID(boolean copyUIDGID);

/**
* If this flag is set to true, all children of the local directory will be copied to the remote without the root directory. For ex: if
* I have root/titi and root/tata and the remote path is /var/data. dirChildrenOnly = true will create /var/data/titi and /var/data/tata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class CopyArchiveToContainerCmdImpl extends AbstrDockerCmd<CopyArchiveToC

private boolean dirChildrenOnly = false;

private boolean copyUIDGID = false;

public CopyArchiveToContainerCmdImpl(CopyArchiveToContainerCmd.Exec exec, String containerId) {
super(exec);
withContainerId(containerId);
Expand All @@ -56,6 +58,12 @@ public CopyArchiveToContainerCmd withNoOverwriteDirNonDir(boolean noOverwriteDir
return this;
}

@Override
public CopyArchiveToContainerCmd withCopyUIDGID(boolean copyUIDGID) {
this.copyUIDGID = copyUIDGID;
return this;
}

@Override
public CopyArchiveToContainerCmd withRemotePath(String remotePath) {
checkNotNull(remotePath, "remotePath was not specified");
Expand Down Expand Up @@ -106,10 +114,15 @@ public boolean isDirChildrenOnly() {
return this.dirChildrenOnly;
}

@Override
public boolean isCopyUIDGID() {
return this.copyUIDGID;
}

@Override
public String toString() {
return new ToStringBuilder(this).append("cp ").append(hostResource).append(" ").append(containerId).append(":")
.append(remotePath).toString();
return new ToStringBuilder(this).append("cp ").append(String.format("-a=%b ", isCopyUIDGID()))
.append(hostResource).append(" ").append(containerId).append(":").append(remotePath).toString();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ protected Void execute(CopyArchiveToContainerCmd command) {
InputStream streamToUpload = command.getTarInputStream();

webResource.queryParam("path", command.getRemotePath())
.queryParam("noOverwriteDirNonDir", command.isNoOverwriteDirNonDir()).request()
.queryParam("noOverwriteDirNonDir", command.isNoOverwriteDirNonDir())
.queryParam("copyUIDGID", command.isCopyUIDGID())
.request()
.put(streamToUpload, MediaType.APPLICATION_X_TAR);

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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.utils.LogContainerTestCallback;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.slf4j.Logger;
Expand All @@ -14,12 +15,16 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeThat;

public class CopyArchiveToContainerCmdIT extends CmdIT {
public static final Logger LOG = LoggerFactory.getLogger(CopyArchiveToContainerCmdIT.class);
Expand Down Expand Up @@ -143,4 +148,71 @@ public void copyFileWithExecutePermission() throws Exception {
assertThat(exitCode, equalTo(0));
}

@Test
public void copyFileWithUIDGID() throws Exception {
Path with = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.with"));
Files.write(with, "with".getBytes());

Path without = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.without"));
Files.write(without, "without".getBytes());

String containerCmd = "while [ ! -f /home/uidgid.with ]; do true; done && stat -c %n:%u /home/uidgid.with /home/uidgid.without";
Long syncUserUid = 4L; // sync user in busybox uses uid=4
CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox")
.withName("copyFileWithUIDGID")
.withCmd("/bin/sh", "-c", containerCmd)
.withUser(syncUserUid.toString())
.exec();
// start the container
dockerRule.getClient().startContainerCmd(container.getId()).exec();

dockerRule.getClient().copyArchiveToContainerCmd(container.getId())
.withRemotePath("/home/")
.withHostResource(without.toString())
.withCopyUIDGID(false)
.exec();
dockerRule.getClient().copyArchiveToContainerCmd(container.getId())
.withRemotePath("/home/")
.withHostResource(with.toString())
.withCopyUIDGID(true)
.exec();

// await exit code
int exitCode = dockerRule.getClient().waitContainerCmd(container.getId())
.start()
.awaitStatusCode();
// check result
assertThat(exitCode, equalTo(0));

LogContainerTestCallback loggingCallback = new LogContainerTestCallback(true);

dockerRule.getClient().logContainerCmd(container.getId())
.withStdOut(true)
.withTailAll()
.exec(loggingCallback);

loggingCallback.awaitCompletion(3, TimeUnit.SECONDS);
String containerOutput = loggingCallback.toString();

assertThat(containerOutput, containsString(String.format("/home/uidgid.with:%d", syncUserUid)));

Long hostUid = getHostUidIfPossible();
assumeThat("could not get the uid on host platform", hostUid, notNullValue(Long.class));
assertThat(containerOutput, containsString(String.format("/home/uidgid.without:%d", hostUid)));
}

private static Long getHostUidIfPossible() {
try {
Class<?> unixSystemClazz = Class.forName("com.sun.security.auth.module.UnixSystem");
Object unixSystem = unixSystemClazz.newInstance();
Object uid = unixSystemClazz.getMethod("getUid").invoke(unixSystem);
if (uid == null) {
return null;
}

return uid instanceof Long ? (Long) uid : Long.parseLong(uid.toString());
} catch (Exception e) {
return null;
}
}
}

0 comments on commit d7db365

Please sign in to comment.