diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java index b3428f7c5..6a4b09a12 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java @@ -197,7 +197,16 @@ public Execution() { } String command = launcher.isUnix() ? "cat" : "cmd.exe"; - container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ command); + String whoAmI = dockerClient.whoAmI(); + if (dockerClient.isRootless()) { + listener.getLogger().println("Running in rootless mode."); + whoAmI = ""; + if (dockerClient.getEngine().equals("podman")) { + listener.getLogger().println("Podman detected."); + step.args = step.args == null ? "--userns=keep-id" : "--userns=keep-id " + step.args; + } + } + container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, whoAmI, /* expected to hang until killed */ command); final List ps = dockerClient.listProcess(env, container); if (!ps.contains(command)) { listener.error( diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/DockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/DockerClient.java index b36b6fd91..26dfd4fc0 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/DockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/DockerClient.java @@ -31,6 +31,7 @@ import hudson.FilePath; import hudson.Launcher; import hudson.model.Node; +import hudson.model.TaskListener; import hudson.util.ArgumentListBuilder; import hudson.util.VersionNumber; import java.io.BufferedReader; @@ -318,6 +319,12 @@ private LaunchResult launch(@NonNull EnvVars launchEnv, boolean quiet, FilePath return result; } + private String executeCommand(String... command) throws IOException, InterruptedException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + launcher.launch().cmds(command).quiet(true).stdout(output).start().joinWithTimeout(CLIENT_TIMEOUT, TimeUnit.SECONDS, launcher.getListener()); + return output.toString(Charset.defaultCharset()).trim(); + } + /** * Who is executing this {@link DockerClient} instance. * @@ -328,15 +335,34 @@ public String whoAmI() throws IOException, InterruptedException { // Windows does not support username return ""; } - ByteArrayOutputStream userId = new ByteArrayOutputStream(); - launcher.launch().cmds("id", "-u").quiet(true).stdout(userId).start().joinWithTimeout(CLIENT_TIMEOUT, TimeUnit.SECONDS, launcher.getListener()); - ByteArrayOutputStream groupId = new ByteArrayOutputStream(); - launcher.launch().cmds("id", "-g").quiet(true).stdout(groupId).start().joinWithTimeout(CLIENT_TIMEOUT, TimeUnit.SECONDS, launcher.getListener()); + String userId = executeCommand("id", "-u"); + String groupId = executeCommand("id", "-g"); - final String charsetName = Charset.defaultCharset().name(); - return String.format("%s:%s", userId.toString(charsetName).trim(), groupId.toString(charsetName).trim()); + return String.format("%s:%s", userId, groupId); + } + + public String getEngine() throws IOException, InterruptedException { + + String engine = "docker"; + + String cmd = executeCommand("docker", "--version"); + if (cmd.toLowerCase().contains("podman")) { + engine = "podman"; + } + else { + String rootless = executeCommand("docker", "info", "-f", "{{.SecurityOptions}}" ); + if (rootless.toLowerCase().contains("rootless")) { + engine = "docker-rootless"; + } + } + + return engine; + } + public boolean isRootless() throws IOException, InterruptedException { + String engine = getEngine(); + return engine.equals("docker-rootless") || engine.equals("podman"); } private static final Pattern hostnameMount = Pattern.compile("/containers/([a-z0-9]{64})/hostname");