From b830f92a4c4806aaf638b7c37339a120b9a05ed1 Mon Sep 17 00:00:00 2001 From: kwall Date: Tue, 27 Sep 2022 18:12:24 +0100 Subject: [PATCH 1/3] Fix #1258: Support copyUIDGID option in CopyArchiveToContainerCmd Signed-off-by: kwall --- .../command/CopyArchiveToContainerCmd.java | 9 +++ .../CopyArchiveToContainerCmdImpl.java | 17 ++++- .../exec/CopyArchiveToContainerCmdExec.java | 4 +- .../cmd/CopyArchiveToContainerCmdIT.java | 70 +++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java index a4dfb5c03..19b3c3843 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java @@ -16,6 +16,7 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd { boolean isDirChildrenOnly(); + boolean isCopyUIDGID(); /** * Set container's id * @@ -49,6 +50,14 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd { */ 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 diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java index cac15fadf..a915a3b02 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java @@ -31,6 +31,8 @@ public class CopyArchiveToContainerCmdImpl extends AbstrDockerCmd 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; + } + } } From daf854379ce932fbaf5cf700cd9b4fd7a9d31c15 Mon Sep 17 00:00:00 2001 From: kwall Date: Wed, 28 Sep 2022 12:06:25 +0100 Subject: [PATCH 2/3] test fix - run test container as non-root. --- .../cmd/CopyArchiveToContainerCmdIT.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java index 8f18ce616..70cba7dda 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java @@ -16,6 +16,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -158,10 +160,11 @@ public void copyFileWithUIDGID() throws Exception { Path without = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.without")); Files.write(without, "with".getBytes()); - String containerCmd = "while [ ! -f /home/uidgid.with ]; do true; done && stat -c %n:%u /home/uidgid.with /home/uidgid.without"; + String containerCmd = "while [ ! -f /home/uidgid.with ]; do true; done && echo uid=$(id -u) && stat -c %n:%u /home/uidgid.with /home/uidgid.without"; CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") .withName("copyFileWithUIDGID") .withCmd("/bin/sh", "-c", containerCmd) + .withUser("sync") .exec(); // start the container dockerRule.getClient().startContainerCmd(container.getId()).exec(); @@ -192,11 +195,18 @@ public void copyFileWithUIDGID() throws Exception { .exec(loggingCallback); loggingCallback.awaitCompletion(3, TimeUnit.SECONDS); - assertThat(loggingCallback.toString(), containsString("/home/uidgid.with:0")); + String containerOutput = loggingCallback.toString(); + + Matcher uidMatcher = Pattern.compile("uid=(\\d+)").matcher(containerOutput); + assertThat(String.format("cannot read effective uid on container from '%s'", containerOutput), uidMatcher.find(), equalTo(true)); + assertThat(String.format("cannot read effective uid on container from '%s'", containerOutput), uidMatcher.groupCount(), equalTo(1)); + Long containerEffectiveUid = Long.parseLong(uidMatcher.group(1)); + + assertThat(containerOutput, containsString(String.format("/home/uidgid.with:%d", containerEffectiveUid))); Long hostUid = getHostUidIfPossible(); assumeThat("could not get the uid on host platform", hostUid, notNullValue(Long.class)); - assertThat(loggingCallback.toString(), containsString(String.format("/home/uidgid.without:%d", hostUid))); + assertThat(containerOutput, containsString(String.format("/home/uidgid.without:%d", hostUid))); } private static Long getHostUidIfPossible() { From f2fa0750783bd06b1e274b09bf83f565618cf2eb Mon Sep 17 00:00:00 2001 From: kwall Date: Wed, 28 Sep 2022 15:52:04 +0100 Subject: [PATCH 3/3] simplify by starting container with numeric uid to avoid the need to look it up --- .../cmd/CopyArchiveToContainerCmdIT.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java index 70cba7dda..d2a0a3406 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java @@ -16,8 +16,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -152,19 +150,18 @@ public void copyFileWithExecutePermission() throws Exception { @Test public void copyFileWithUIDGID() throws Exception { - Path withDir = Files.createTempDirectory("copyFileWithUIDGID"); Path with = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.with")); Files.write(with, "with".getBytes()); - Path withoutDir = Files.createTempDirectory("copyFileWithUIDGID"); Path without = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.without")); - Files.write(without, "with".getBytes()); + Files.write(without, "without".getBytes()); - String containerCmd = "while [ ! -f /home/uidgid.with ]; do true; done && echo uid=$(id -u) && stat -c %n:%u /home/uidgid.with /home/uidgid.without"; + 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("sync") + .withUser(syncUserUid.toString()) .exec(); // start the container dockerRule.getClient().startContainerCmd(container.getId()).exec(); @@ -197,12 +194,7 @@ public void copyFileWithUIDGID() throws Exception { loggingCallback.awaitCompletion(3, TimeUnit.SECONDS); String containerOutput = loggingCallback.toString(); - Matcher uidMatcher = Pattern.compile("uid=(\\d+)").matcher(containerOutput); - assertThat(String.format("cannot read effective uid on container from '%s'", containerOutput), uidMatcher.find(), equalTo(true)); - assertThat(String.format("cannot read effective uid on container from '%s'", containerOutput), uidMatcher.groupCount(), equalTo(1)); - Long containerEffectiveUid = Long.parseLong(uidMatcher.group(1)); - - assertThat(containerOutput, containsString(String.format("/home/uidgid.with:%d", containerEffectiveUid))); + 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));