From 3b2e7dc53d7c5c9b9323873849658abca23de5b3 Mon Sep 17 00:00:00 2001 From: Jesse Awan Date: Tue, 1 Jun 2021 09:59:49 +0200 Subject: [PATCH] add initContainer capabilities (#2820) * set init container capabilities * set init container capabilities * correct parameter definition + change assertThat Co-authored-by: Adnan Awan Co-authored-by: Thorsten Duda --- .../DockerExecuteOnKubernetesTest.groovy | 44 ++++++++++++++++++- vars/dockerExecuteOnKubernetes.groovy | 42 +++++++++++++++++- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/test/groovy/DockerExecuteOnKubernetesTest.groovy b/test/groovy/DockerExecuteOnKubernetesTest.groovy index f8a9e1340..a0b50d422 100644 --- a/test/groovy/DockerExecuteOnKubernetesTest.groovy +++ b/test/groovy/DockerExecuteOnKubernetesTest.groovy @@ -676,7 +676,6 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest { def expectedSecurityContext = [runAsUser: 1000, fsGroup: 1000] nullScript.commonPipelineEnvironment.configuration = [general: [jenkinsKubernetes: [ securityContext: expectedSecurityContext]]] - stepRule.step.dockerExecuteOnKubernetes( script: nullScript, juStabUtils: utils, @@ -803,11 +802,12 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest { script: nullScript, juStabUtils: utils, containerName: 'mycontainer', + initContainerImage: 'ppiper/cf-cli', dockerImage: 'maven:3.5-jdk-8-alpine', containerMountPath: '/opt', ) { bodyExecuted = true } - def containerSpec = podSpec.spec.containers.find{it.image == "maven:3.5-jdk-8-alpine"} + def initContainerSpec = podSpec.spec.initContainers[0] assertTrue(bodyExecuted) assertEquals( [[ @@ -819,6 +819,46 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest { "name" : "volume", "mountPath": "/opt" ]], containerSpec.volumeMounts) + assertEquals( + [[ + "name" : "volume", + "mountPath": "/opt" + ]], initContainerSpec.volumeMounts) + } + + @Test + void testInitContainerDefaultWithParameters() { + stepRule.step.dockerExecuteOnKubernetes( + script: nullScript, + juStabUtils: utils, + containerName: 'mycontainer', + initContainerImage: 'ppiper/cf-cli@sha256:latest', + initContainerCommand: 'cp /usr/local/bin/cf7 /opt/bin/cf', + dockerImage: 'maven:3.5-jdk-8-alpine', + containerMountPath: '/opt', + ) { bodyExecuted = true } + def initContainer = podSpec.spec.initContainers[0] + def expectedCommandOutput = ["sh", "-c", "cp /usr/local/bin/cf7 /opt/bin/cf"] + assertTrue(bodyExecuted) + assertEquals("ppiper-cf-cli-sha256-latest", initContainer.name) + assertEquals("ppiper/cf-cli@sha256:latest", initContainer.image) + assertThat(initContainer.command, is(equalTo(expectedCommandOutput))) + } + + @Test + void testInitContainerWithoutContainerCommand() { + stepRule.step.dockerExecuteOnKubernetes( + script: nullScript, + juStabUtils: utils, + containerName: 'mycontainer', + initContainerImage: 'ppiper/cf-cli@sha256:latest', + dockerImage: 'maven:3.5-jdk-8-alpine', + containerMountPath: '/opt', + ) { bodyExecuted = true } + def initContainer = podSpec.spec.initContainers[0] + def expectedCommandOutput = ["/usr/bin/tail", "-f", "/dev/null"] + assertTrue(bodyExecuted) + assertThat(initContainer.command, is(equalTo(expectedCommandOutput))) } private container(options, body) { diff --git a/vars/dockerExecuteOnKubernetes.groovy b/vars/dockerExecuteOnKubernetes.groovy index aa8ce8fdd..0f25ad36a 100644 --- a/vars/dockerExecuteOnKubernetes.groovy +++ b/vars/dockerExecuteOnKubernetes.groovy @@ -198,6 +198,15 @@ import hudson.AbortException * use this volume in an initContainer. */ 'containerMountPath', + /** + * The docker image to run as initContainer. + */ + 'initContainerImage', + /** + * Command executed inside the init container shell. Please enter command without providing any "sh -c" prefix. For example for an echo message, simply enter: echo `HelloWorld` + */ + 'initContainerCommand', + ]) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.minus([ 'stashIncludes', @@ -336,6 +345,7 @@ private String generatePodSpec(Map config) { spec : [:] ] podSpec.spec += getAdditionalPodProperties(config) + podSpec.spec.initContainers = getInitContainerList(config) podSpec.spec.containers = getContainerList(config) podSpec.spec.securityContext = getSecurityContext(config) @@ -349,7 +359,6 @@ private String generatePodSpec(Map config) { return new JsonUtils().groovyObjectToPrettyJsonString(podSpec) } - private String stashWorkspace(config, prefix, boolean chown = false, boolean stashBack = false) { def stashName = "${prefix}-${config.uniqueId}" try { @@ -416,6 +425,36 @@ private void unstashWorkspace(config, prefix) { } } +private List getInitContainerList(config){ + def initContainerSpecList = [] + if (config.initContainerImage && config.containerMountPath) { + // regex [\W_] matches any non-word character equivalent to [^a-zA-Z0-9_] + def initContainerName = config.initContainerImage.toLowerCase().replaceAll(/[\W_]/,"-" ) + def initContainerSpec = [ + name : initContainerName, + image : config.initContainerImage + ] + if (config.containerMountPath) { + initContainerSpec.volumeMounts = [[name: "volume", mountPath: config.containerMountPath]] + } + if (config.initContainerCommand == null) { + initContainerSpec['command'] = [ + '/usr/bin/tail', + '-f', + '/dev/null' + ] + } else { + initContainerSpec['command'] = [ + 'sh', + '-c', + config.initContainerCommand + ] + } + initContainerSpecList.push(initContainerSpec) + } + return initContainerSpecList +} + private List getContainerList(config) { //If no custom jnlp agent provided as default jnlp agent (jenkins/jnlp-slave) as defined in the plugin, see https://github.com/jenkinsci/kubernetes-plugin#pipeline-support @@ -497,7 +536,6 @@ private List getContainerList(config) { env : getContainerEnvs(config, config.sidecarImage, config.sidecarEnvVars, config.sidecarWorkspace), command : [] ] - def resources = getResources(sideCarContainerName, config) if(resources) { containerSpec.resources = resources