From de54b46ae95666c31e77e66a4ae1b39213a127b9 Mon Sep 17 00:00:00 2001 From: Dharmendra Gupta Date: Sun, 13 Dec 2020 14:35:59 +0530 Subject: [PATCH 1/5] fixed JENKINS-60473 --- .../docker/workflow/WithContainerStep.java | 144 ++++++++++------- .../docker/workflow/client/DockerClient.java | 140 +++++++++------- .../workflow/client/WindowsDockerClient.java | 150 +++++++++++++++++- 3 files changed, 312 insertions(+), 122 deletions(-) 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 ebbfd68a3..12b5f1ad1 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java @@ -25,40 +25,17 @@ import com.google.common.base.Optional; import com.google.inject.Inject; -import hudson.AbortException; -import hudson.EnvVars; -import hudson.Extension; -import hudson.FilePath; -import hudson.Launcher; -import hudson.LauncherDecorator; -import hudson.Proc; -import hudson.Util; +import hudson.*; import hudson.model.Computer; import hudson.model.Node; import hudson.model.Run; import hudson.model.TaskListener; import hudson.slaves.WorkspaceList; import hudson.util.VersionNumber; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; import org.jenkinsci.plugins.docker.commons.tools.DockerTool; import org.jenkinsci.plugins.docker.workflow.client.DockerClient; import org.jenkinsci.plugins.docker.workflow.client.WindowsDockerClient; -import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; -import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; -import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; -import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; -import org.jenkinsci.plugins.workflow.steps.BodyInvoker; -import org.jenkinsci.plugins.workflow.steps.StepContext; -import org.jenkinsci.plugins.workflow.steps.StepContextParameter; +import org.jenkinsci.plugins.workflow.steps.*; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; @@ -68,22 +45,26 @@ import java.io.IOException; import java.io.Serializable; import java.nio.charset.Charset; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; public class WithContainerStep extends AbstractStepImpl { - + private static final Logger LOGGER = Logger.getLogger(WithContainerStep.class.getName()); - private final @Nonnull String image; + private final @Nonnull + String image; private String args; private String toolName; + private static boolean needToContainerizePath = false; - @DataBoundConstructor public WithContainerStep(@Nonnull String image) { + @DataBoundConstructor + public WithContainerStep(@Nonnull String image) { this.image = image; } - + public String getImage() { return image; } @@ -101,7 +82,8 @@ public String getToolName() { return toolName; } - @DataBoundSetter public void setToolName(String toolName) { + @DataBoundSetter + public void setToolName(String toolName) { this.toolName = Util.fixEmpty(toolName); } @@ -112,22 +94,31 @@ private static void destroy(String container, Launcher launcher, Node node, EnvV // TODO switch to GeneralNonBlockingStepExecution public static class Execution extends AbstractStepExecutionImpl { private static final long serialVersionUID = 1; - @Inject(optional=true) private transient WithContainerStep step; - @StepContextParameter private transient Launcher launcher; - @StepContextParameter private transient TaskListener listener; - @StepContextParameter private transient FilePath workspace; - @StepContextParameter private transient EnvVars env; - @StepContextParameter private transient Computer computer; - @StepContextParameter private transient Node node; + @Inject(optional = true) + private transient WithContainerStep step; + @StepContextParameter + private transient Launcher launcher; + @StepContextParameter + private transient TaskListener listener; + @StepContextParameter + private transient FilePath workspace; + @StepContextParameter + private transient EnvVars env; + @StepContextParameter + private transient Computer computer; + @StepContextParameter + private transient Node node; @SuppressWarnings("rawtypes") // TODO not compiling on cloudbees.ci - @StepContextParameter private transient Run run; + @StepContextParameter + private transient Run run; private String container; private String toolName; public Execution() { } - @Override public boolean start() throws Exception { + @Override + public boolean start() throws Exception { EnvVars envReduced = new EnvVars(env); EnvVars envHost = computer.getEnvironment(); envReduced.entrySet().removeAll(envHost.entrySet()); @@ -140,10 +131,19 @@ public Execution() { workspace.mkdirs(); // otherwise it may be owned by root when created for -v String ws = getPath(workspace); toolName = step.toolName; + DockerClient dockerClient = launcher.isUnix() ? new DockerClient(launcher, node, toolName) : new WindowsDockerClient(launcher, node, toolName); + String containerOsType = dockerClient.inspect(new EnvVars(), step.image, ".Os"); + + if (!launcher.isUnix() && containerOsType != null && containerOsType.equalsIgnoreCase("linux")) { + needToContainerizePath = true; + dockerClient.setNeedToContainerizePath(true); + dockerClient.setContainerUnix(true); + } + VersionNumber dockerVersion = dockerClient.version(); if (dockerVersion != null) { if (dockerVersion.isOlderThan(new VersionNumber("1.7"))) { @@ -194,7 +194,13 @@ public Execution() { volumes.put(tmp, tmp); } - String command = launcher.isUnix() ? "cat" : "cmd.exe"; + String command; + if (containerOsType != null && containerOsType.equalsIgnoreCase("linux")) { + command = "cat"; + } else { + command = "cmd.exe"; + } + container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ command); final List ps = dockerClient.listProcess(env, container); if (!ps.contains(command)) { @@ -207,9 +213,9 @@ public Execution() { ImageAction.add(step.image, run); getContext().newBodyInvoker(). - withContext(BodyInvoker.mergeLauncherDecorators(getContext().get(LauncherDecorator.class), new Decorator(container, envHost, ws, toolName, dockerVersion))). - withCallback(new Callback(container, toolName)). - start(); + withContext(BodyInvoker.mergeLauncherDecorators(getContext().get(LauncherDecorator.class), new Decorator(container, envHost, ws, toolName, dockerVersion))). + withCallback(new Callback(container, toolName)). + start(); return false; } @@ -227,7 +233,8 @@ private static FilePath tempDir(FilePath ws) { return ws.sibling(ws.getName() + System.getProperty(WorkspaceList.class.getName(), "@") + "tmp"); } - @Override public void stop(@Nonnull Throwable cause) throws Exception { + @Override + public void stop(@Nonnull Throwable cause) throws Exception { if (container != null) { LOGGER.log(Level.FINE, "stopping container " + container, cause); destroy(container, launcher, getContext().get(Node.class), env, toolName); @@ -242,7 +249,8 @@ private static class Decorator extends LauncherDecorator implements Serializable private final String container; private final String[] envHost; private final String ws; - private final @CheckForNull String toolName; + private final @CheckForNull + String toolName; private final boolean hasEnv; private final boolean hasWorkdir; @@ -255,9 +263,11 @@ private static class Decorator extends LauncherDecorator implements Serializable this.hasWorkdir = dockerVersion != null && dockerVersion.compareTo(new VersionNumber("17.12")) >= 0; } - @Override public Launcher decorate(final Launcher launcher, final Node node) { + @Override + public Launcher decorate(final Launcher launcher, final Node node) { return new Launcher.DecoratedLauncher(launcher) { - @Override public Proc launch(Launcher.ProcStarter starter) throws IOException { + @Override + public Proc launch(Launcher.ProcStarter starter) throws IOException { String executable; try { executable = getExecutable(); @@ -311,8 +321,8 @@ private static class Decorator extends LauncherDecorator implements Serializable masksPrefixList.add(false); prefix.addAll(envReduced); masksPrefixList.addAll(envReduced.stream() - .map(v -> true) - .collect(Collectors.toList())); + .map(v -> true) + .collect(Collectors.toList())); } boolean[] originalMasks = starter.masks(); @@ -332,17 +342,28 @@ private static class Decorator extends LauncherDecorator implements Serializable System.arraycopy(originalMasks, 0, masks, prefix.size(), originalMasks.length); starter.masks(masks); + if (needToContainerizePath && ws != null) { + String wsTrimmed = ws.replaceAll("[/\\\\]+$", ""); + List cmds = starter.cmds(); + for (int i = 0; i < cmds.size(); i++) { + cmds.set(i, WindowsDockerClient.containerizePath(cmds.get(i), wsTrimmed)); + } + } + return super.launch(starter); } - @Override public void kill(Map modelEnvVars) throws IOException, InterruptedException { + + @Override + public void kill(Map modelEnvVars) throws IOException, InterruptedException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); String executable = getExecutable(); if (getInner().launch().cmds(executable, "exec", container, "ps", "-A", "-o", "pid,command", "e").stdout(baos).quiet(true).start().joinWithTimeout(DockerClient.CLIENT_TIMEOUT, TimeUnit.SECONDS, listener) != 0) { throw new IOException("failed to run ps"); } List pids = new ArrayList(); - LINE: for (String line : baos.toString(Charset.defaultCharset().name()).split("\n")) { - for (Map.Entry entry : modelEnvVars.entrySet()) { + LINE: + for (String line : baos.toString(Charset.defaultCharset().name()).split("\n")) { + for (Map.Entry entry : modelEnvVars.entrySet()) { // TODO this is imprecise: false positive when argv happens to match KEY=value even if environment does not. Cf. trick in BourneShellScript. if (!line.contains(entry.getKey() + "=" + entry.getValue())) { continue LINE; @@ -364,6 +385,7 @@ private static class Decorator extends LauncherDecorator implements Serializable } } } + private String getExecutable() throws IOException, InterruptedException { EnvVars env = new EnvVars(); for (String pair : envHost) { @@ -387,31 +409,37 @@ private static class Callback extends BodyExecutionCallback.TailCall { this.toolName = toolName; } - @Override protected void finished(StepContext context) throws Exception { + @Override + protected void finished(StepContext context) throws Exception { destroy(container, context.get(Launcher.class), context.get(Node.class), context.get(EnvVars.class), toolName); } } - @Extension public static class DescriptorImpl extends AbstractStepDescriptorImpl { + @Extension + public static class DescriptorImpl extends AbstractStepDescriptorImpl { public DescriptorImpl() { super(Execution.class); } - @Override public String getFunctionName() { + @Override + public String getFunctionName() { return "withDockerContainer"; } - @Override public String getDisplayName() { + @Override + public String getDisplayName() { return "Run build steps inside a Docker container"; } - @Override public boolean takesImplicitBlockArgument() { + @Override + public boolean takesImplicitBlockArgument() { return true; } - @Override public boolean isAdvanced() { + @Override + public boolean isAdvanced() { return true; } 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 336efa0bb..80ebb167e 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,38 +31,28 @@ import hudson.model.Node; import hudson.util.ArgumentListBuilder; import hudson.util.VersionNumber; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.docker.commons.fingerprint.ContainerRecord; +import org.jenkinsci.plugins.docker.commons.tools.DockerTool; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import java.io.*; import java.nio.charset.Charset; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.CheckForNull; -import javax.annotation.Nonnull; -import org.apache.commons.lang.StringUtils; -import org.jenkinsci.plugins.docker.commons.fingerprint.ContainerRecord; -import org.jenkinsci.plugins.docker.commons.tools.DockerTool; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Simple docker client for Pipeline. - * + * * @author tom.fennelly@gmail.com */ public class DockerClient { @@ -72,23 +62,27 @@ public class DockerClient { /** * Maximum amount of time (in seconds) to wait for {@code docker} client operations which are supposed to be more or less instantaneous. */ - @SuppressFBWarnings(value="MS_SHOULD_BE_FINAL", justification="mutable for scripts") + @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "mutable for scripts") @Restricted(NoExternalUse.class) public static int CLIENT_TIMEOUT = Integer.getInteger(DockerClient.class.getName() + ".CLIENT_TIMEOUT", 180); // TODO 2.4+ SystemProperties /** * Skip removal of container after a container has been stopped. */ - @SuppressFBWarnings(value="MS_SHOULD_BE_FINAL", justification="mutable for scripts") + @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "mutable for scripts") @Restricted(NoExternalUse.class) public static boolean SKIP_RM_ON_STOP = Boolean.getBoolean(DockerClient.class.getName() + ".SKIP_RM_ON_STOP"); // e.g. 2015-04-09T13:40:21.981801679Z public static final String DOCKER_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; - + private final Launcher launcher; - private final @CheckForNull Node node; - private final @CheckForNull String toolName; + private final @CheckForNull + Node node; + private final @CheckForNull + String toolName; + private boolean needToContainerizePath = false; + private boolean isContainerUnix = true; public DockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckForNull String toolName) { this.launcher = launcher; @@ -99,15 +93,15 @@ public DockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckF /** * Run a docker image. * - * @param launchEnv Docker client launch environment. - * @param image The image name. - * @param args Any additional arguments for the {@code docker run} command. - * @param workdir The working directory in the container, or {@code null} for default. - * @param volumes Volumes to be bound. Supply an empty list if no volumes are to be bound. + * @param launchEnv Docker client launch environment. + * @param image The image name. + * @param args Any additional arguments for the {@code docker run} command. + * @param workdir The working directory in the container, or {@code null} for default. + * @param volumes Volumes to be bound. Supply an empty list if no volumes are to be bound. * @param volumesFromContainers Mounts all volumes from the given containers. - * @param containerEnv Environment variables to set in container. - * @param user The uid:gid to execute the container command as. Use {@link #whoAmI()}. - * @param command The command to execute in the image container being run. + * @param containerEnv Environment variables to set in container. + * @param user The uid:gid to execute the container command as. Use {@link #whoAmI()}. + * @param command The command to execute in the image container being run. * @return The container ID. */ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNull String args, @CheckForNull String workdir, @Nonnull Map volumes, @Nonnull Collection volumesFromContainers, @Nonnull EnvVars containerEnv, @Nonnull String user, @Nonnull String... command) throws IOException, InterruptedException { @@ -122,7 +116,7 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu if (args != null) { argb.addTokenized(args); } - + if (workdir != null) { argb.add("-w", workdir); } @@ -134,7 +128,7 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu } for (Map.Entry variable : containerEnv.entrySet()) { argb.add("-e"); - argb.addMasked(variable.getKey()+"="+variable.getValue()); + argb.addMasked(variable.getKey() + "=" + variable.getValue()); } argb.add(image).add(command); @@ -159,7 +153,7 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont while ((line = in.readLine()) != null) { final StringTokenizer stringTokenizer = new StringTokenizer(line, " "); if (stringTokenizer.countTokens() < 2) { - throw new IOException("Unexpected `docker top` output : "+line); + throw new IOException("Unexpected `docker top` output : " + line); } stringTokenizer.nextToken(); // PID processes.add(stringTokenizer.nextToken()); // COMMAND @@ -170,12 +164,12 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont /** * Stop a container. - * - *

+ * + *

* Also removes ({@link #rm(EnvVars, String)}) the container if property * SKIP_RM_ON_STOP is unset or equals false. - * - * @param launchEnv Docker client launch environment. + * + * @param launchEnv Docker client launch environment. * @param containerId The container ID. */ public void stop(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { @@ -190,8 +184,8 @@ public void stop(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws /** * Remove a container. - * - * @param launchEnv Docker client launch environment. + * + * @param launchEnv Docker client launch environment. * @param containerId The container ID. */ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { @@ -204,12 +198,14 @@ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws I /** * Inspect a docker image/container. + * * @param launchEnv Docker client launch environment. - * @param objectId The image/container ID. + * @param objectId The image/container ID. * @param fieldPath The data path of the data required e.g. {@code .NetworkSettings.IPAddress}. * @return The inspected field value. Null if the command failed */ - public @CheckForNull String inspect(@Nonnull EnvVars launchEnv, @Nonnull String objectId, @Nonnull String fieldPath) throws IOException, InterruptedException { + public @CheckForNull + String inspect(@Nonnull EnvVars launchEnv, @Nonnull String objectId, @Nonnull String fieldPath) throws IOException, InterruptedException { LaunchResult result = launch(launchEnv, true, "inspect", "-f", String.format("{{%s}}", fieldPath), objectId); if (result.getStatus() == 0) { return result.getOut(); @@ -217,27 +213,30 @@ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws I return null; } } - + /** * Inspect a docker image/container. + * * @param launchEnv Docker client launch environment. - * @param objectId The image/container ID. + * @param objectId The image/container ID. * @param fieldPath The data path of the data required e.g. {@code .NetworkSettings.IPAddress}. * @return The inspected field value. May be an empty string - * @throws IOException Execution error. Also fails if cannot retrieve the requested field from the request + * @throws IOException Execution error. Also fails if cannot retrieve the requested field from the request * @throws InterruptedException Interrupted * @since 1.1 */ - public @Nonnull String inspectRequiredField(@Nonnull EnvVars launchEnv, @Nonnull String objectId, - @Nonnull String fieldPath) throws IOException, InterruptedException { + public @Nonnull + String inspectRequiredField(@Nonnull EnvVars launchEnv, @Nonnull String objectId, + @Nonnull String fieldPath) throws IOException, InterruptedException { final String fieldValue = inspect(launchEnv, objectId, fieldPath); if (fieldValue == null) { throw new IOException("Cannot retrieve " + fieldPath + " from 'docker inspect " + objectId + "'"); } return fieldValue; } - - private @CheckForNull Date getCreatedDate(@Nonnull EnvVars launchEnv, @Nonnull String objectId) throws IOException, InterruptedException { + + private @CheckForNull + Date getCreatedDate(@Nonnull EnvVars launchEnv, @Nonnull String objectId) throws IOException, InterruptedException { String createdString = inspect(launchEnv, objectId, "json .Created"); if (createdString == null) { return null; @@ -257,7 +256,8 @@ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws I * @return The {@link VersionNumber} instance if the version string matches the expected format, * otherwise {@code null}. */ - public @CheckForNull VersionNumber version() throws IOException, InterruptedException { + public @CheckForNull + VersionNumber version() throws IOException, InterruptedException { LaunchResult result = launch(new EnvVars(), true, "-v"); if (result.getStatus() == 0) { return parseVersionNumber(result.getOut()); @@ -265,10 +265,12 @@ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws I return null; } } - + private static final Pattern pattern = Pattern.compile("^(\\D+)(\\d+)\\.(\\d+)\\.(\\d+)(.*)"); + /** * Parse a Docker version string (e.g. "Docker version 1.5.0, build a8a31ef"). + * * @param versionString The version string to parse. * @return The {@link VersionNumber} instance if the version string matched the * expected format, otherwise {@code null}. @@ -282,15 +284,17 @@ protected static VersionNumber parseVersionNumber(@Nonnull String versionString) return new VersionNumber(String.format("%s.%s.%s", major, minor, maint)); } else { return null; - } + } } private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, @Nonnull String... args) throws IOException, InterruptedException { return launch(launchEnv, quiet, null, args); } + private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, FilePath pwd, @Nonnull String... args) throws IOException, InterruptedException { return launch(launchEnv, quiet, pwd, new ArgumentListBuilder(args)); } + private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, FilePath pwd, @Nonnull ArgumentListBuilder args) throws IOException, InterruptedException { // Prepend the docker command args.prepend(DockerTool.getExecutable(toolName, node, launcher.getListener(), launchEnv)); @@ -363,17 +367,18 @@ public ContainerRecord getContainerRecord(@Nonnull EnvVars launchEnv, String con // TODO get tags and add for ContainerRecord return new ContainerRecord(host, containerId, image, containerName, - (created != null ? created.getTime() : 0L), - Collections.emptyMap()); + (created != null ? created.getTime() : 0L), + Collections.emptyMap()); } /** * Inspect the mounts of a container. * These might have been declared {@code VOLUME}s, or mounts defined via {@code --volume}. - * @param launchEnv Docker client launch environment. + * + * @param launchEnv Docker client launch environment. * @param containerID The container ID. * @return a list of filesystem paths inside the container - * @throws IOException Execution error. Also fails if cannot retrieve the requested field from the request + * @throws IOException Execution error. Also fails if cannot retrieve the requested field from the request * @throws InterruptedException Interrupted */ public List getVolumes(@Nonnull EnvVars launchEnv, String containerID) throws IOException, InterruptedException { @@ -388,4 +393,21 @@ public List getVolumes(@Nonnull EnvVars launchEnv, String containerID) t } return Arrays.asList(volumes.replace("\\", "/").split("\\n")); } + + public boolean isNeedToContainerizePath() { + return needToContainerizePath; + } + + public void setNeedToContainerizePath(boolean needToContainerizePath) { + this.needToContainerizePath = needToContainerizePath; + } + + public boolean isContainerUnix() { + return isContainerUnix; + } + + public void setContainerUnix(boolean containerUnix) { + isContainerUnix = containerUnix; + } + } diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java index 2de11c25d..845937cda 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java @@ -22,6 +22,8 @@ public class WindowsDockerClient extends DockerClient { private final Launcher launcher; private final Node node; + private boolean needToContainerizePath = false; + private boolean isContainerUnix = false; public WindowsDockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckForNull String toolName) { super(launcher, node, toolName); @@ -37,10 +39,10 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu } if (workdir != null) { - argb.add("-w", workdir); + argb.add("-w", containerizePathIfNeeded(workdir)); } for (Map.Entry volume : volumes.entrySet()) { - argb.add("-v", volume.getKey() + ":" + volume.getValue()); + argb.add("-v", volume.getKey() + ":" + containerizePathIfNeeded(volume.getValue())); } for (String containerId : volumesFromContainers) { argb.add("--volumes-from", containerId); @@ -61,6 +63,9 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu @Override public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { + if (isContainerUnix) { + return listProcessUnixContainer(launchEnv, containerId); + } LaunchResult result = launch(launchEnv, false, null, "docker", "top", containerId); if (result.getStatus() != 0) { throw new IOException(String.format("Failed to run top '%s'. Error: %s", containerId, result.getErr())); @@ -73,7 +78,7 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont while ((line = in.readLine()) != null) { final StringTokenizer stringTokenizer = new StringTokenizer(line, " "); if (stringTokenizer.countTokens() < 1) { - throw new IOException("Unexpected `docker top` output : "+line); + throw new IOException("Unexpected `docker top` output : " + line); } processes.add(stringTokenizer.nextToken()); // COMMAND @@ -82,6 +87,30 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont return processes; } + public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { + LaunchResult result = launch(launchEnv, false, null, "docker", "top", containerId); + if (result.getStatus() != 0) { + throw new IOException(String.format("Failed to run top '%s'. Error: %s", containerId, result.getErr())); + } + List processes = new ArrayList<>(); + try (Reader r = new StringReader(result.getOut()); + BufferedReader in = new BufferedReader(r)) { + String line; + in.readLine(); // ps header + while ((line = in.readLine()) != null) { + final StringTokenizer stringTokenizer = new StringTokenizer(line, " "); + if (stringTokenizer.countTokens() < 4) { + throw new IOException("Unexpected `docker top` output : "+line); + } + stringTokenizer.nextToken(); // PID + stringTokenizer.nextToken(); // USER + stringTokenizer.nextToken(); // TIME + processes.add(stringTokenizer.nextToken()); // COMMAND + } + } + return processes; + } + @Override public Optional getContainerIdIfContainerized() throws IOException, InterruptedException { if (node == null || @@ -90,13 +119,13 @@ public Optional getContainerIdIfContainerized() throws IOException, Inte } LaunchResult getComputerName = launch(new EnvVars(), true, null, "hostname"); - if(getComputerName.getStatus() != 0) { + if (getComputerName.getStatus() != 0) { throw new IOException("Failed to get hostname."); } String shortID = getComputerName.getOut().toLowerCase(); LaunchResult getLongIdResult = launch(new EnvVars(), true, null, "docker", "inspect", shortID, "--format={{.Id}}"); - if(getLongIdResult.getStatus() != 0) { + if (getLongIdResult.getStatus() != 0) { LOGGER.log(Level.INFO, "Running inside of a container but cannot determine container ID from current environment."); return Optional.absent(); } @@ -115,6 +144,7 @@ public String whoAmI() throws IOException, InterruptedException { private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, String... args) throws IOException, InterruptedException { return launch(env, quiet, workDir, new ArgumentListBuilder(args)); } + private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, ArgumentListBuilder argb) throws IOException, InterruptedException { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Executing command \"{0}\"", argb); @@ -135,4 +165,114 @@ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, Argume return result; } + + public boolean isNeedToContainerizePath() { + return needToContainerizePath; + } + + public void setNeedToContainerizePath(boolean needToContainerizePath) { + this.needToContainerizePath = needToContainerizePath; + } + + public boolean isContainerUnix() { + return isContainerUnix; + } + + public void setContainerUnix(boolean containerUnix) { + isContainerUnix = containerUnix; + } + + public String containerizePathIfNeeded(String path) { + return containerizePathIfNeeded(path, null); + } + + public String containerizePathIfNeeded(String path, String prefix) { + if (this.needToContainerizePath) + return WindowsDockerClient.containerizePath(path, prefix); + return path; + } + + public static String containerizePath(String path, String prefix) { + StringBuffer result = new StringBuffer(); + char[] pathChars = path.toCharArray(); + char[] prefixChars = (prefix == null) ? null : prefix.toCharArray(); + + for (int i = 0; i < pathChars.length; i++) { + char currentChar = pathChars[i]; + if (currentChar == ':' && i > 0 && i < pathChars.length - 1) { + char previousChar = pathChars[i - 1]; + if ((previousChar >= 'a' && previousChar <= 'z') || (previousChar >= 'A' && previousChar <= 'Z')) { + char nextChar = pathChars[i + 1]; + if (nextChar == '/' || nextChar == '\\') { + char nextNextChar = (i < pathChars.length - 2) ? pathChars[i + 2] : ' '; + if (nextNextChar != '/') { + if (prefix == null || checkPrefix(pathChars, i - 1, prefixChars)) { + result.setCharAt(i - 1, '/'); + result.append(Character.toLowerCase(previousChar)); + result.append('/'); + i++; + i++; + + boolean done = false; + for (; i < pathChars.length; i++) { + currentChar = pathChars[i]; + switch (currentChar) { + case '\\': + result.append('/'); + break; + + case '?': + case '<': + case '>': + case ':': + case '*': + case '|': + case '"': + case '\'': + result.append(currentChar); + done = true; + break; + + default: + result.append(currentChar); + break; + } + + if (done) + break; + } + + continue; + } + } + } + } + } + + result.append(currentChar); + + } + return result.toString(); + + } + + private static boolean checkPrefix(char[] pathChars, int index, char[] prefixChars) { + if (index + prefixChars.length > pathChars.length) + return false; + + for (int i = 0; i < prefixChars.length; i++) { + char pathChar = pathChars[index + i]; + if (pathChar == '\\') + pathChar = '/'; + + char prefixChar = prefixChars[i]; + if (prefixChar == '\\') + prefixChar = '/'; + + if (pathChar != prefixChar) + return false; + } + + return true; + } } From d801256faee4ec689570d5ce584c83267abd44d4 Mon Sep 17 00:00:00 2001 From: Dharmendra Gupta Date: Sun, 13 Dec 2020 15:41:31 +0530 Subject: [PATCH 2/5] removed ambigous if-else --- .../plugins/docker/workflow/WithContainerStep.java | 7 +------ .../plugins/docker/workflow/client/DockerClient.java | 4 ++++ .../docker/workflow/client/WindowsDockerClient.java | 8 ++++++++ 3 files changed, 13 insertions(+), 6 deletions(-) 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 12b5f1ad1..f306b0903 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java @@ -194,12 +194,7 @@ public boolean start() throws Exception { volumes.put(tmp, tmp); } - String command; - if (containerOsType != null && containerOsType.equalsIgnoreCase("linux")) { - command = "cat"; - } else { - command = "cmd.exe"; - } + String command = dockerClient.runCommand(); container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ command); final List ps = dockerClient.listProcess(env, container); 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 80ebb167e..a9a844f2f 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 @@ -394,6 +394,10 @@ public List getVolumes(@Nonnull EnvVars launchEnv, String containerID) t return Arrays.asList(volumes.replace("\\", "/").split("\\n")); } + public String runCommand() { + return "cat"; + } + public boolean isNeedToContainerizePath() { return needToContainerizePath; } diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java index 845937cda..cacedb4a5 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java @@ -111,6 +111,14 @@ public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnul return processes; } + @Override + public String runCommand() { + if(isContainerUnix) { + return "cat"; + } + return "cmd"; + } + @Override public Optional getContainerIdIfContainerized() throws IOException, InterruptedException { if (node == null || From b04197fffae06486e3523ff3fb325f47f17fb279 Mon Sep 17 00:00:00 2001 From: Dharmendra Gupta Date: Mon, 14 Dec 2020 14:45:13 +0530 Subject: [PATCH 3/5] added javadoc --- .../docker/workflow/client/DockerClient.java | 104 ++++++++++++++-- .../workflow/client/WindowsDockerClient.java | 113 +++++++++++++++++- 2 files changed, 208 insertions(+), 9 deletions(-) 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 a9a844f2f..8cf4dce04 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 @@ -73,7 +73,10 @@ public class DockerClient { @Restricted(NoExternalUse.class) public static boolean SKIP_RM_ON_STOP = Boolean.getBoolean(DockerClient.class.getName() + ".SKIP_RM_ON_STOP"); - // e.g. 2015-04-09T13:40:21.981801679Z + /** + * The constant DOCKER_DATE_TIME_FORMAT. + */ +// e.g. 2015-04-09T13:40:21.981801679Z public static final String DOCKER_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private final Launcher launcher; @@ -84,6 +87,13 @@ public class DockerClient { private boolean needToContainerizePath = false; private boolean isContainerUnix = true; + /** + * Instantiates a new Docker client. + * + * @param launcher the launcher + * @param node the node + * @param toolName the tool name + */ public DockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckForNull String toolName) { this.launcher = launcher; this.node = node; @@ -103,6 +113,8 @@ public DockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckF * @param user The uid:gid to execute the container command as. Use {@link #whoAmI()}. * @param command The command to execute in the image container being run. * @return The container ID. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNull String args, @CheckForNull String workdir, @Nonnull Map volumes, @Nonnull Collection volumesFromContainers, @Nonnull EnvVars containerEnv, @Nonnull String user, @Nonnull String... command) throws IOException, InterruptedException { ArgumentListBuilder argb = new ArgumentListBuilder(); @@ -140,6 +152,15 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu } } + /** + * List process list. + * + * @param launchEnv the launch env + * @param containerId the container id + * @return list list + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception + */ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { LaunchResult result = launch(launchEnv, false, "top", containerId, "-eo", "pid,comm"); if (result.getStatus() != 0) { @@ -171,6 +192,8 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont * * @param launchEnv Docker client launch environment. * @param containerId The container ID. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public void stop(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { LaunchResult result = launch(launchEnv, false, "stop", "--time=1", containerId); @@ -187,6 +210,8 @@ public void stop(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws * * @param launchEnv Docker client launch environment. * @param containerId The container ID. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { LaunchResult result; @@ -203,6 +228,8 @@ public void rm(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws I * @param objectId The image/container ID. * @param fieldPath The data path of the data required e.g. {@code .NetworkSettings.IPAddress}. * @return The inspected field value. Null if the command failed + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public @CheckForNull String inspect(@Nonnull EnvVars launchEnv, @Nonnull String objectId, @Nonnull String fieldPath) throws IOException, InterruptedException { @@ -253,8 +280,9 @@ Date getCreatedDate(@Nonnull EnvVars launchEnv, @Nonnull String objectId) throws /** * Get the docker version. * - * @return The {@link VersionNumber} instance if the version string matches the expected format, - * otherwise {@code null}. + * @return The {@link VersionNumber} instance if the version string matches the expected format, otherwise {@code null}. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public @CheckForNull VersionNumber version() throws IOException, InterruptedException { @@ -272,8 +300,7 @@ VersionNumber version() throws IOException, InterruptedException { * Parse a Docker version string (e.g. "Docker version 1.5.0, build a8a31ef"). * * @param versionString The version string to parse. - * @return The {@link VersionNumber} instance if the version string matched the - * expected format, otherwise {@code null}. + * @return The {@link VersionNumber} instance if the version string matched the expected format, otherwise {@code null}. */ protected static VersionNumber parseVersionNumber(@Nonnull String versionString) { Matcher matcher = pattern.matcher(versionString.trim()); @@ -287,14 +314,40 @@ protected static VersionNumber parseVersionNumber(@Nonnull String versionString) } } + /** + * @param launchEnv + * @param quiet + * @param args + * @return + * @throws IOException + * @throws InterruptedException + */ private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, @Nonnull String... args) throws IOException, InterruptedException { return launch(launchEnv, quiet, null, args); } + /** + * @param launchEnv + * @param quiet + * @param pwd + * @param args + * @return + * @throws IOException + * @throws InterruptedException + */ private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, FilePath pwd, @Nonnull String... args) throws IOException, InterruptedException { return launch(launchEnv, quiet, pwd, new ArgumentListBuilder(args)); } + /** + * @param launchEnv + * @param quiet + * @param pwd + * @param args + * @return + * @throws IOException + * @throws InterruptedException + */ private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, FilePath pwd, @Nonnull ArgumentListBuilder args) throws IOException, InterruptedException { // Prepend the docker command args.prepend(DockerTool.getExecutable(toolName, node, launcher.getListener(), launchEnv)); @@ -323,6 +376,8 @@ private LaunchResult launch(@Nonnull EnvVars launchEnv, boolean quiet, FilePath * Who is executing this {@link DockerClient} instance. * * @return a {@link String} containing the uid:gid. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ public String whoAmI() throws IOException, InterruptedException { if (!launcher.isUnix()) { @@ -344,8 +399,9 @@ public String whoAmI() throws IOException, InterruptedException { * Checks if this {@link DockerClient} instance is running inside a container and returns the id of the container * if so. * - * @return an optional string containing the container id, or absent if - * it isn't containerized. + * @return an optional string containing the container id, or absent if it isn't containerized. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception * @see Discussion */ public Optional getContainerIdIfContainerized() throws IOException, InterruptedException { @@ -359,6 +415,15 @@ public Optional getContainerIdIfContainerized() throws IOException, Inte return ControlGroup.getContainerId(cgroupFile); } + /** + * Gets container record. + * + * @param launchEnv the launch env + * @param containerId the container id + * @return the container record + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception + */ public ContainerRecord getContainerRecord(@Nonnull EnvVars launchEnv, String containerId) throws IOException, InterruptedException { String host = inspectRequiredField(launchEnv, containerId, ".Config.Hostname"); String containerName = inspectRequiredField(launchEnv, containerId, ".Name"); @@ -394,22 +459,47 @@ public List getVolumes(@Nonnull EnvVars launchEnv, String containerID) t return Arrays.asList(volumes.replace("\\", "/").split("\\n")); } + /** + * Run command string. + * + * @return the string + */ public String runCommand() { return "cat"; } + /** + * Is need to containerize path boolean. + * + * @return the boolean + */ public boolean isNeedToContainerizePath() { return needToContainerizePath; } + /** + * Sets need to containerize path. + * + * @param needToContainerizePath the need to containerize path + */ public void setNeedToContainerizePath(boolean needToContainerizePath) { this.needToContainerizePath = needToContainerizePath; } + /** + * Is container unix boolean. + * + * @return the boolean + */ public boolean isContainerUnix() { return isContainerUnix; } + /** + * Sets container unix. + * + * @param containerUnix the container unix + */ public void setContainerUnix(boolean containerUnix) { isContainerUnix = containerUnix; } diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java index cacedb4a5..8201b19bb 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java @@ -17,6 +17,9 @@ import java.util.logging.Level; import java.util.logging.Logger; +/** + * The type Windows docker client. + */ public class WindowsDockerClient extends DockerClient { private static final Logger LOGGER = Logger.getLogger(WindowsDockerClient.class.getName()); @@ -25,12 +28,33 @@ public class WindowsDockerClient extends DockerClient { private boolean needToContainerizePath = false; private boolean isContainerUnix = false; + /** + * Instantiates a new Windows docker client. + * + * @param launcher the launcher + * @param node the node + * @param toolName the tool name + */ public WindowsDockerClient(@Nonnull Launcher launcher, @CheckForNull Node node, @CheckForNull String toolName) { super(launcher, node, toolName); this.launcher = launcher; this.node = node; } + /** + * @param launchEnv Docker client launch environment. + * @param image The image name. + * @param args Any additional arguments for the {@code docker run} command. + * @param workdir The working directory in the container, or {@code null} for default. + * @param volumes Volumes to be bound. Supply an empty list if no volumes are to be bound. + * @param volumesFromContainers Mounts all volumes from the given containers. + * @param containerEnv Environment variables to set in container. + * @param user The uid:gid to execute the container command as. Use {@link #whoAmI()}. + * @param command The command to execute in the image container being run. + * @return The container ID. + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception + */ @Override public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNull String args, @CheckForNull String workdir, @Nonnull Map volumes, @Nonnull Collection volumesFromContainers, @Nonnull EnvVars containerEnv, @Nonnull String user, @Nonnull String... command) throws IOException, InterruptedException { ArgumentListBuilder argb = new ArgumentListBuilder("docker", "run", "-d", "-t"); @@ -61,6 +85,13 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu } } + /** + * @param launchEnv the launch env + * @param containerId the container id + * @return + * @throws IOException + * @throws InterruptedException + */ @Override public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { if (isContainerUnix) { @@ -87,6 +118,15 @@ public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String cont return processes; } + /** + * List process unix container list. + * + * @param launchEnv the launch env + * @param containerId the container id + * @return the list + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception + */ public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { LaunchResult result = launch(launchEnv, false, null, "docker", "top", containerId); if (result.getStatus() != 0) { @@ -100,7 +140,7 @@ public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnul while ((line = in.readLine()) != null) { final StringTokenizer stringTokenizer = new StringTokenizer(line, " "); if (stringTokenizer.countTokens() < 4) { - throw new IOException("Unexpected `docker top` output : "+line); + throw new IOException("Unexpected `docker top` output : " + line); } stringTokenizer.nextToken(); // PID stringTokenizer.nextToken(); // USER @@ -111,14 +151,22 @@ public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnul return processes; } + /** + * @return + */ @Override public String runCommand() { - if(isContainerUnix) { + if (isContainerUnix) { return "cat"; } return "cmd"; } + /** + * @return + * @throws IOException + * @throws InterruptedException + */ @Override public Optional getContainerIdIfContainerized() throws IOException, InterruptedException { if (node == null || @@ -141,6 +189,11 @@ public Optional getContainerIdIfContainerized() throws IOException, Inte return Optional.of(getLongIdResult.getOut()); } + /** + * @return + * @throws IOException + * @throws InterruptedException + */ @Override public String whoAmI() throws IOException, InterruptedException { try (ByteArrayOutputStream userId = new ByteArrayOutputStream()) { @@ -149,10 +202,28 @@ public String whoAmI() throws IOException, InterruptedException { } } + /** + * @param env + * @param quiet + * @param workDir + * @param args + * @return + * @throws IOException + * @throws InterruptedException + */ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, String... args) throws IOException, InterruptedException { return launch(env, quiet, workDir, new ArgumentListBuilder(args)); } + /** + * @param env + * @param quiet + * @param workDir + * @param argb + * @return + * @throws IOException + * @throws InterruptedException + */ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, ArgumentListBuilder argb) throws IOException, InterruptedException { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Executing command \"{0}\"", argb); @@ -174,32 +245,64 @@ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, Argume return result; } + /** + * @return + */ public boolean isNeedToContainerizePath() { return needToContainerizePath; } + /** + * @param needToContainerizePath the need to containerize path + */ public void setNeedToContainerizePath(boolean needToContainerizePath) { this.needToContainerizePath = needToContainerizePath; } + /** + * @return + */ public boolean isContainerUnix() { return isContainerUnix; } + /** + * @param containerUnix the container unix + */ public void setContainerUnix(boolean containerUnix) { isContainerUnix = containerUnix; } + /** + * Containerize path if needed string. + * + * @param path the path + * @return the string + */ public String containerizePathIfNeeded(String path) { return containerizePathIfNeeded(path, null); } + /** + * Containerize path if needed string. + * + * @param path the path + * @param prefix the prefix + * @return the string + */ public String containerizePathIfNeeded(String path, String prefix) { if (this.needToContainerizePath) return WindowsDockerClient.containerizePath(path, prefix); return path; } + /** + * Containerize path string. + * + * @param path the path + * @param prefix the prefix + * @return the string + */ public static String containerizePath(String path, String prefix) { StringBuffer result = new StringBuffer(); char[] pathChars = path.toCharArray(); @@ -264,6 +367,12 @@ public static String containerizePath(String path, String prefix) { } + /** + * @param pathChars + * @param index + * @param prefixChars + * @return + */ private static boolean checkPrefix(char[] pathChars, int index, char[] prefixChars) { if (index + prefixChars.length > pathChars.length) return false; From abcaa62e1e70140ac5fe2c257e4a215b84d8b842 Mon Sep 17 00:00:00 2001 From: Dharmendra Gupta Date: Tue, 15 Dec 2020 12:41:33 +0530 Subject: [PATCH 4/5] fixed javadoc issues --- .../workflow/client/WindowsDockerClient.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java index 8201b19bb..e6f4b6d39 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java @@ -88,9 +88,9 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu /** * @param launchEnv the launch env * @param containerId the container id - * @return - * @throws IOException - * @throws InterruptedException + * @return returns Process + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ @Override public List listProcess(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { @@ -152,7 +152,7 @@ public List listProcessUnixContainer(@Nonnull EnvVars launchEnv, @Nonnul } /** - * @return + * @return command to run as entry-point */ @Override public String runCommand() { @@ -163,9 +163,9 @@ public String runCommand() { } /** - * @return - * @throws IOException - * @throws InterruptedException + * @return Container ID + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ @Override public Optional getContainerIdIfContainerized() throws IOException, InterruptedException { @@ -190,9 +190,9 @@ public Optional getContainerIdIfContainerized() throws IOException, Inte } /** - * @return - * @throws IOException - * @throws InterruptedException + * @return Current User + * @throws IOException the io exception + * @throws InterruptedException the interrupted exception */ @Override public String whoAmI() throws IOException, InterruptedException { @@ -207,8 +207,8 @@ public String whoAmI() throws IOException, InterruptedException { * @param quiet * @param workDir * @param args - * @return - * @throws IOException + * @return result of command executed + * @throws IOException the io exception * @throws InterruptedException */ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, String... args) throws IOException, InterruptedException { @@ -246,7 +246,7 @@ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, Argume } /** - * @return + * @return boolean path need to be containerize */ public boolean isNeedToContainerizePath() { return needToContainerizePath; @@ -259,8 +259,9 @@ public void setNeedToContainerizePath(boolean needToContainerizePath) { this.needToContainerizePath = needToContainerizePath; } + /** - * @return + * @return boolean container type (unix or windows) */ public boolean isContainerUnix() { return isContainerUnix; From 95fa43e99771634fb9bcffaafef24440f0508420 Mon Sep 17 00:00:00 2001 From: Dharmendra Gupta Date: Tue, 15 Dec 2020 14:05:34 +0530 Subject: [PATCH 5/5] correctly formatted the file --- .../docker/workflow/client/WindowsDockerClient.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java index e6f4b6d39..3b4052961 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java @@ -89,7 +89,7 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu * @param launchEnv the launch env * @param containerId the container id * @return returns Process - * @throws IOException the io exception + * @throws IOException the io exception * @throws InterruptedException the interrupted exception */ @Override @@ -164,7 +164,7 @@ public String runCommand() { /** * @return Container ID - * @throws IOException the io exception + * @throws IOException the io exception * @throws InterruptedException the interrupted exception */ @Override @@ -191,7 +191,7 @@ public Optional getContainerIdIfContainerized() throws IOException, Inte /** * @return Current User - * @throws IOException the io exception + * @throws IOException the io exception * @throws InterruptedException the interrupted exception */ @Override @@ -208,7 +208,7 @@ public String whoAmI() throws IOException, InterruptedException { * @param workDir * @param args * @return result of command executed - * @throws IOException the io exception + * @throws IOException the io exception * @throws InterruptedException */ private LaunchResult launch(EnvVars env, boolean quiet, FilePath workDir, String... args) throws IOException, InterruptedException {