From 1b62a445dad085a016dff6be89bbbc2d71219876 Mon Sep 17 00:00:00 2001 From: Girondel Etienne Date: Thu, 2 Nov 2023 16:20:51 +0100 Subject: [PATCH] Enable Additional Docker Run Arguments --- .../docker/workflow/WithContainerStep.java | 4 +- .../declarative/DeclarativeDockerUtils.java | 21 ++++++++++ .../declarative/DockerPropertiesProvider.java | 3 ++ .../workflow/declarative/FolderConfig.java | 42 ++++++++++++++++++- .../workflow/declarative/GlobalConfig.java | 15 +++++++ .../declarative/FolderConfig/config.groovy | 3 ++ .../declarative/GlobalConfig/config.groovy | 3 ++ .../DeclarativeDockerUtilsTest.java | 22 +++++++--- .../declarativeDockerConfig.groovy | 1 + ...declarativeDockerConfigWithOverride.groovy | 1 + 10 files changed, 107 insertions(+), 8 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 b3428f7c5..71533fc01 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java @@ -55,6 +55,7 @@ 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.docker.workflow.declarative.DeclarativeDockerUtils; import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; @@ -197,7 +198,8 @@ 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 args = (DeclarativeDockerUtils.getAdditionalRunArgs() + " " + Util.fixNull(step.args)).trim(); + container = dockerClient.run(env, step.image, args, ws, volumes, volumesFromContainers, envReduced, dockerClient.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/declarative/DeclarativeDockerUtils.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtils.java index b680cd371..e473d82be 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtils.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtils.java @@ -85,6 +85,27 @@ public static String getLabel(@Nullable String override) { return null; } + @Whitelisted + public static String getAdditionalRunArgs() { + return getAdditionalRunArgs(null); + } + + @Whitelisted + public static String getAdditionalRunArgs(@Nullable String override) { + if (!StringUtils.isBlank(override)) { + return override; + } else { + Run r = currentRun(); + for (DockerPropertiesProvider provider : DockerPropertiesProvider.all()) { + String additionalRunArgs = provider.getAdditionalRunArgs(r); + if (!StringUtils.isBlank(additionalRunArgs)) { + return additionalRunArgs; + } + } + } + return ""; + } + @Whitelisted public static WithScriptScript getLabelScript(AbstractDockerAgent describable, CpsScript script) throws Exception { String targetLabel = getLabel(describable.getLabel()); diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DockerPropertiesProvider.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DockerPropertiesProvider.java index 7358eceaa..e1d9c4c54 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DockerPropertiesProvider.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/DockerPropertiesProvider.java @@ -44,6 +44,9 @@ public abstract class DockerPropertiesProvider implements ExtensionPoint { @CheckForNull public abstract String getLabel(@Nullable Run run); + @CheckForNull + public abstract String getAdditionalRunArgs(@Nullable Run run); + public static ExtensionList all() { return ExtensionList.lookup(DockerPropertiesProvider.class); } diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig.java index 3bfeb21c4..fdabe4a72 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig.java @@ -31,6 +31,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import hudson.Extension; +import hudson.Util; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Items; @@ -47,6 +48,7 @@ */ public class FolderConfig extends AbstractFolderProperty> { private String dockerLabel; + private String additionalRunArgs; private DockerRegistryEndpoint registry; @DataBoundConstructor @@ -60,8 +62,9 @@ public FolderConfig() { * @param url The registry URL * @param creds the registry credentials ID */ - public FolderConfig(String dockerLabel, String url, String creds) { + public FolderConfig(String dockerLabel, String additionalRunArgs, String url, String creds) { this.dockerLabel = dockerLabel; + this.additionalRunArgs = additionalRunArgs; this.registry = new DockerRegistryEndpoint(url, creds); } @@ -69,11 +72,20 @@ public String getDockerLabel() { return dockerLabel; } + public String getAdditionalRunArgs() { + return Util.fixNull(additionalRunArgs); + } + @DataBoundSetter public void setDockerLabel(String dockerLabel) { this.dockerLabel = dockerLabel; } + @DataBoundSetter + public void setAdditionalRunArgs(String additionalArgs) { + this.additionalRunArgs = additionalArgs; + } + public DockerRegistryEndpoint getRegistry() { return registry; } @@ -128,6 +140,34 @@ public String getLabel(@Nullable Run run) { return null; } + @Override + public String getAdditionalRunArgs(@Nullable Run run) { + if (run != null) { + Job job = run.getParent(); + ItemGroup parent = job.getParent(); + while (parent != null) { + + if (parent instanceof AbstractFolder) { + AbstractFolder folder = (AbstractFolder) parent; + FolderConfig config = (FolderConfig) folder.getProperties().get(FolderConfig.class); + if (config != null) { + String additionalRunArgs = config.getAdditionalRunArgs(); + if (!StringUtils.isBlank(additionalRunArgs)) { + return additionalRunArgs; + } + } + } + + if (parent instanceof Item) { + parent = ((Item) parent).getParent(); + } else { + parent = null; + } + } + } + return ""; + } + @Override public String getRegistryUrl(@Nullable Run run) { if (run != null) { diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig.java index 7099f423f..2886509a3 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig.java @@ -57,6 +57,7 @@ public class GlobalConfig extends GlobalConfiguration { private static final Logger LOGGER = Logger.getLogger(GlobalConfig.class.getName()); private String dockerLabel; + private String additionalRunArgs; private DockerRegistryEndpoint registry; public GlobalConfig() { @@ -79,11 +80,20 @@ public String getDockerLabel() { return Util.fixEmpty(dockerLabel); } + public String getAdditionalRunArgs() { + return Util.fixNull(additionalRunArgs); + } + @DataBoundSetter public void setDockerLabel(String dockerLabel) { this.dockerLabel = dockerLabel; } + @DataBoundSetter + public void setAdditionalRunArgs(String additionalRunArgs) { + this.additionalRunArgs = additionalRunArgs; + } + public DockerRegistryEndpoint getRegistry() { return registry; } @@ -114,6 +124,11 @@ public String getLabel(@Nullable Run run) { return config.getDockerLabel(); } + @Override + public String getAdditionalRunArgs(@Nullable Run run) { + return config.getAdditionalRunArgs(); + } + @Override public String getRegistryUrl(@Nullable Run run) { if (config.getRegistry() != null && !StringUtils.isBlank(config.getRegistry().getUrl())) { diff --git a/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig/config.groovy b/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig/config.groovy index 42598d495..eed4542cd 100644 --- a/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/FolderConfig/config.groovy @@ -31,4 +31,7 @@ def f = namespace(lib.FormTagLib) f.entry(field: "dockerLabel", title: _("Docker Label")) { f.textbox() } +f.entry(field: "additionalRunArgs", title:_("Docker Additional Run Arguments")) { + f.textbox() +} f.property(field: "registry") diff --git a/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig/config.groovy b/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig/config.groovy index 3f1d49155..185df2463 100644 --- a/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/docker/workflow/declarative/GlobalConfig/config.groovy @@ -32,5 +32,8 @@ f.section(title:_("Declarative Pipeline (Docker)")) { f.entry(field: "dockerLabel", title:_("Docker Label")) { f.textbox() } + f.entry(field: "additionalRunArgs", title:_("Docker Additional Run Arguments")) { + f.textbox() + } f.property(field: "registry") } diff --git a/src/test/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtilsTest.java b/src/test/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtilsTest.java index 85f1a0eb1..7627ea7e7 100644 --- a/src/test/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtilsTest.java +++ b/src/test/java/org/jenkinsci/plugins/docker/workflow/declarative/DeclarativeDockerUtilsTest.java @@ -82,8 +82,10 @@ public void plainSystemConfig() throws Exception { Assume.assumeFalse("Fails using the version of Git installed on the Windows ACI agents on ci.jenkins.io", Functions.isWindows()); GlobalConfig.get().setDockerLabel("config_docker"); GlobalConfig.get().setRegistry(new DockerRegistryEndpoint("https://docker.registry", globalCred.getId())); + GlobalConfig.get().setAdditionalRunArgs("-v /tmp:/tmptest:ro,z"); expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig") .logContains("Docker Label is: config_docker", + "Docker Run Additional Arguments are: -v /tmp:/tmptest:ro,z", "Registry URL is: https://docker.registry", "Registry Creds ID is: " + globalCred.getId()).go(); } @@ -100,11 +102,12 @@ public void testExtensionOrdinal() { public void directParent() throws Exception { Folder folder = j.createProject(Folder.class); getFolderStore(folder).addCredentials(Domain.global(), folderCred); - folder.addProperty(new FolderConfig("folder_docker", "https://folder.registry", folderCred.getId())); + folder.addProperty(new FolderConfig("folder_docker", "", "https://folder.registry", folderCred.getId())); expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig") .inFolder(folder) .runFromRepo(false) .logContains("Docker Label is: folder_docker", + "Docker Run Additional Arguments are: ", "Registry URL is: https://folder.registry", "Registry Creds ID is: " + folderCred.getId()).go(); } @@ -114,11 +117,12 @@ public void withDefaults() throws Exception { Folder folder = j.createProject(Folder.class); getFolderStore(folder).addCredentials(Domain.global(), folderCred); getFolderStore(folder).addCredentials(Domain.global(), grandParentCred); - folder.addProperty(new FolderConfig("folder_docker", "https://folder.registry", folderCred.getId())); + folder.addProperty(new FolderConfig("folder_docker", "", "https://folder.registry", folderCred.getId())); expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfigWithOverride") .inFolder(folder) .runFromRepo(false) .logContains("Docker Label is: other-label", + "Docker Run Additional Arguments are: ", "Registry URL is: https://other.registry", "Registry Creds ID is: " + grandParentCred.getId()).go(); } @@ -126,17 +130,20 @@ public void withDefaults() throws Exception { @Test public void directParentNotSystem() throws Exception { GlobalConfig.get().setDockerLabel("config_docker"); + GlobalConfig.get().setAdditionalRunArgs("-v /tmp:/tmp1:ro,z"); GlobalConfig.get().setRegistry(new DockerRegistryEndpoint("https://docker.registry", globalCred.getId())); Folder folder = j.createProject(Folder.class); getFolderStore(folder).addCredentials(Domain.global(), folderCred); - folder.addProperty(new FolderConfig("folder_docker", "https://folder.registry", folderCred.getId())); + folder.addProperty(new FolderConfig("folder_docker", "-v /tmp:/tmp2:ro,z", "https://folder.registry", folderCred.getId())); expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig") .inFolder(folder) .runFromRepo(false) .logContains("Docker Label is: folder_docker", + "Docker Run Additional Arguments are: -v /tmp:/tmp2:ro,z", "Registry URL is: https://folder.registry", "Registry Creds ID is: " + folderCred.getId()) .logNotContains("Docker Label is: config_docker", + "Docker Run Additional Arguments are: -v /tmp:/tmp1:ro,z", "Registry URL is: https://docker.registry", "Registry Creds ID is: " + globalCred.getId()).go(); } @@ -145,12 +152,13 @@ public void directParentNotSystem() throws Exception { public void grandParent() throws Exception { Folder grandParent = j.createProject(Folder.class); getFolderStore(grandParent).addCredentials(Domain.global(), grandParentCred); - grandParent.addProperty(new FolderConfig("parent_docker", "https://parent.registry", grandParentCred.getId())); + grandParent.addProperty(new FolderConfig("parent_docker", "", "https://parent.registry", grandParentCred.getId())); Folder parent = grandParent.createProject(Folder.class, "testParent"); //Can be static since grandParent should be unique expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig") .inFolder(parent) .runFromRepo(false) .logContains("Docker Label is: parent_docker", + "Docker Run Additional Arguments are: ", "Registry URL is: https://parent.registry", "Registry Creds ID is: " + grandParentCred.getId()).go(); } @@ -159,18 +167,20 @@ public void grandParent() throws Exception { public void grandParentOverride() throws Exception { Folder grandParent = j.createProject(Folder.class); getFolderStore(grandParent).addCredentials(Domain.global(), grandParentCred); - grandParent.addProperty(new FolderConfig("parent_docker", "https://parent.registry", grandParentCred.getId())); + grandParent.addProperty(new FolderConfig("parent_docker", "-v /tmp:/tmp1:ro,z", "https://parent.registry", grandParentCred.getId())); Folder parent = grandParent.createProject(Folder.class, "testParent"); //Can be static since grandParent should be unique getFolderStore(parent).addCredentials(Domain.global(), folderCred); - parent.addProperty(new FolderConfig("folder_docker", "https://folder.registry", folderCred.getId())); + parent.addProperty(new FolderConfig("folder_docker", "-v /tmp:/tmp2:ro,z", "https://folder.registry", folderCred.getId())); expect("org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig") .inFolder(parent) .runFromRepo(false) .logContains("Docker Label is: folder_docker", + "Docker Run Additional Arguments are: -v /tmp:/tmp2:ro,z", "Registry URL is: https://folder.registry", "Registry Creds ID is: " + folderCred.getId()) .logNotContains("Docker Label is: parent_docker", + "Docker Run Additional Arguments are: -v /tmp:/tmp1:ro,z", "Registry URL is: https://parent.registry", "Registry Creds ID is: " + grandParentCred.getId()).go(); } diff --git a/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig.groovy b/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig.groovy index 65a2d7bad..d22ab06fa 100644 --- a/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig.groovy +++ b/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfig.groovy @@ -26,5 +26,6 @@ import org.jenkinsci.plugins.docker.workflow.declarative.DeclarativeDockerUtils echo "Docker Label is: ${DeclarativeDockerUtils.getLabel()}" +echo "Docker Run Additional Arguments are: ${DeclarativeDockerUtils.getAdditionalRunArgs()}" echo "Registry URL is: ${DeclarativeDockerUtils.getRegistryUrl()}" echo "Registry Creds ID is: ${DeclarativeDockerUtils.getRegistryCredentialsId()}" \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfigWithOverride.groovy b/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfigWithOverride.groovy index ea717a558..eb68802fb 100644 --- a/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfigWithOverride.groovy +++ b/src/test/resources/org/jenkinsci/plugins/docker/workflow/declarative/declarativeDockerConfigWithOverride.groovy @@ -25,5 +25,6 @@ import org.jenkinsci.plugins.docker.workflow.declarative.DeclarativeDockerUtils echo "Docker Label is: ${DeclarativeDockerUtils.getLabel('other-label')}" +echo "Docker Run Additional Arguments are: ${DeclarativeDockerUtils.getAdditionalRunArgs()}" echo "Registry URL is: ${DeclarativeDockerUtils.getRegistryUrl('https://other.registry')}" echo "Registry Creds ID is: ${DeclarativeDockerUtils.getRegistryCredentialsId('grandParentCreds')}"