mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-03-05 15:15:44 +02:00
* Define pod using k8s yaml manifest The Kubernetes plugin allows to define pods directly via the Kubernetes API specification: https://github.com/jenkinsci/kubernetes-plugin#using-yaml-to-define-pod-templates This has the advantage of unlocking Kubernetes features which are not exposed via the Kubernetes plugin, including all Kubernetes security featues. Using the Kubernetes API directly is also better from development point of view because it is stable and better desgined then the API the plugin offers. * Make the Kubernetes ns configurable If one Jenkins Master is used by multiple Teams, it is desirable to schedule K8S workloads in seperatae workspaces. * Add securityContext to define uid and fsGroup In the context of the Jenkins k8s plugin it is uids and fsGroups play an important role, because the containers share a common file system. Therefore it is benefical to configure this data centraly. * fix indention * Undo format changes * Extend and fix unit tests * Fix port mapping * Don't set uid globally This does not work with jaas due to permissions problems. * Fix sidecar test * Make security context configurable at stage level * Extract json serialization * Cleanup unit tests
379 lines
14 KiB
Groovy
379 lines
14 KiB
Groovy
import com.sap.piper.JenkinsUtils
|
|
|
|
import org.junit.Before
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.junit.rules.ExpectedException
|
|
import org.junit.rules.RuleChain
|
|
|
|
|
|
import groovy.json.JsonSlurper
|
|
import util.BasePiperTest
|
|
import util.JenkinsDockerExecuteRule
|
|
import util.JenkinsLoggingRule
|
|
import util.JenkinsReadYamlRule
|
|
import util.JenkinsShellCallRule
|
|
import util.JenkinsStepRule
|
|
import util.PluginMock
|
|
import util.Rules
|
|
|
|
import static org.hamcrest.Matchers.*
|
|
import static org.junit.Assert.assertThat
|
|
import static org.junit.Assert.assertTrue
|
|
import static org.junit.Assert.assertEquals
|
|
import static org.junit.Assert.assertFalse
|
|
|
|
class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
|
private ExpectedException exception = ExpectedException.none()
|
|
private JenkinsDockerExecuteRule dockerExecuteRule = new JenkinsDockerExecuteRule(this)
|
|
private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this)
|
|
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
|
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
|
|
|
@Rule
|
|
public RuleChain ruleChain = Rules
|
|
.getCommonRules(this)
|
|
.around(new JenkinsReadYamlRule(this))
|
|
.around(exception)
|
|
.around(dockerExecuteRule)
|
|
.around(shellRule)
|
|
.around(loggingRule)
|
|
.around(stepRule)
|
|
int whichDockerReturnValue = 0
|
|
def bodyExecuted
|
|
def dockerImage
|
|
def containerMap
|
|
def dockerEnvVars
|
|
def dockerWorkspace
|
|
def podName = ''
|
|
def podLabel = ''
|
|
def containersList = []
|
|
def imageList = []
|
|
def containerName = ''
|
|
def containerShell = ''
|
|
def envList = []
|
|
def portList = []
|
|
def containerCommands = []
|
|
def pullImageMap = [:]
|
|
def namespace
|
|
def securityContext
|
|
|
|
@Before
|
|
void init() {
|
|
containersList = []
|
|
imageList = []
|
|
envList = []
|
|
portList = []
|
|
containerCommands = []
|
|
bodyExecuted = false
|
|
JenkinsUtils.metaClass.static.isPluginActive = { def s -> new PluginMock(s).isActive() }
|
|
helper.registerAllowedMethod('sh', [Map.class], {return whichDockerReturnValue})
|
|
helper.registerAllowedMethod('container', [Map.class, Closure.class], { Map config, Closure body -> container(config){body()}
|
|
})
|
|
helper.registerAllowedMethod('podTemplate', [Map.class, Closure.class], { Map options, Closure body ->
|
|
podName = options.name
|
|
podLabel = options.label
|
|
namespace = options.namespace
|
|
def podSpec = new JsonSlurper().parseText(options.yaml) // this yaml is actually json
|
|
def containers = podSpec.spec.containers
|
|
securityContext = podSpec.spec.securityContext
|
|
|
|
containers.each { container ->
|
|
containersList.add(container.name)
|
|
imageList.add(container.image.toString())
|
|
envList.add(container.env)
|
|
if(container.ports) {
|
|
portList.add(container.ports)
|
|
}
|
|
if (container.command) {
|
|
containerCommands.add(container.command)
|
|
}
|
|
pullImageMap.put(container.image.toString(), container.imagePullPolicy == "Always")
|
|
}
|
|
body()
|
|
})
|
|
}
|
|
|
|
@Test
|
|
void testRunOnPodNoContainerMapOnlyDockerImage() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerOptions: '-it',
|
|
dockerVolumeBind: ['my_vol': '/my_vol'],
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000'], dockerWorkspace: '/home/piper'
|
|
){
|
|
bodyExecuted = true
|
|
}
|
|
assertThat(containersList, hasItem('container-exec'))
|
|
assertThat(imageList, hasItem('maven:3.5-jdk-8-alpine'))
|
|
assertThat(envList.toString(), containsString('http_proxy'))
|
|
assertThat(envList.toString(), containsString('http://proxy:8000'))
|
|
assertThat(envList.toString(), containsString('/home/piper'))
|
|
assertThat(bodyExecuted, is(true))
|
|
assertThat(containerCommands.size(), is(1))
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomContainerMap() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(script: nullScript,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute']) {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertEquals('mavenexecute', containerName)
|
|
assertTrue(containersList.contains('mavenexecute'))
|
|
assertTrue(imageList.contains('maven:3.5-jdk-8-alpine'))
|
|
assertTrue(bodyExecuted)
|
|
assertThat(containerCommands.size(), is(1))
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomJnlpWithContainerMap() throws Exception {
|
|
nullScript.commonPipelineEnvironment.configuration = ['general': ['jenkinsKubernetes': ['jnlpAgent': 'myJnalpAgent']]]
|
|
stepRule.step.dockerExecuteOnKubernetes(script: nullScript,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute']) {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertEquals('mavenexecute', containerName)
|
|
assertTrue(containersList.contains('mavenexecute'))
|
|
assertTrue(imageList.contains('maven:3.5-jdk-8-alpine'))
|
|
assertTrue(containersList.contains('jnlp'))
|
|
assertTrue(imageList.contains('myJnalpAgent'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomJnlpWithDockerImage() throws Exception {
|
|
nullScript.commonPipelineEnvironment.configuration = ['general': ['jenkinsKubernetes': ['jnlpAgent': 'myJnalpAgent']]]
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine') {
|
|
bodyExecuted = true
|
|
}
|
|
assertEquals('container-exec', containerName)
|
|
assertTrue(containersList.contains('jnlp'))
|
|
assertTrue(containersList.contains('container-exec'))
|
|
assertTrue(imageList.contains('myJnalpAgent'))
|
|
assertTrue(imageList.contains('maven:3.5-jdk-8-alpine'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomWorkspace() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(script: nullScript,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute'],
|
|
dockerWorkspace: '/home/piper') {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertTrue(envList.toString().contains('/home/piper'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomEnv() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(script: nullScript,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute'],
|
|
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertTrue(envList.toString().contains('customEnvKey') && envList.toString().contains('customEnvValue'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesUpperCaseContainerName() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(script: nullScript,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'MAVENEXECUTE'],
|
|
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertEquals('mavenexecute', containerName)
|
|
assertTrue(containersList.contains('mavenexecute'))
|
|
assertTrue(imageList.contains('maven:3.5-jdk-8-alpine'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesEmptyContainerMapNoDockerImage() throws Exception {
|
|
exception.expect(IllegalArgumentException.class);
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
containerMap: [:],
|
|
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
|
container(name: 'jnlp') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertFalse(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testSidecarDefault() {
|
|
List portMapping = []
|
|
helper.registerAllowedMethod('portMapping', [Map.class], {m ->
|
|
portMapping.add(m)
|
|
return m
|
|
})
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
containerCommands: ['selenium/standalone-chrome': ''],
|
|
containerEnvVars: [
|
|
'selenium/standalone-chrome': ['customEnvKey': 'customEnvValue']
|
|
],
|
|
containerMap: [
|
|
'maven:3.5-jdk-8-alpine': 'mavenexecute',
|
|
'selenium/standalone-chrome': 'selenium'
|
|
],
|
|
containerName: 'mavenexecute',
|
|
containerPortMappings: [
|
|
'selenium/standalone-chrome': [[containerPort: 4444, hostPort: 4444]]
|
|
],
|
|
containerWorkspaces: [
|
|
'selenium/standalone-chrome': ''
|
|
],
|
|
dockerWorkspace: '/home/piper'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
|
|
assertThat(bodyExecuted, is(true))
|
|
assertThat(containerName, is('mavenexecute'))
|
|
|
|
assertThat(containersList, allOf(
|
|
hasItem('jnlp'),
|
|
hasItem('mavenexecute'),
|
|
hasItem('selenium'),
|
|
))
|
|
assertThat(imageList, allOf(
|
|
hasItem('s4sdk/jenkins-agent-k8s:latest'),
|
|
hasItem('maven:3.5-jdk-8-alpine'),
|
|
hasItem('selenium/standalone-chrome'),
|
|
))
|
|
// assertThat(portList, is(null))
|
|
assertThat(portList, hasItem([[name: 'selenium0', containerPort: 4444, hostPort: 4444]]))
|
|
assertThat(containerCommands.size(), is(1))
|
|
assertThat(envList, hasItem(hasItem(allOf(hasEntry('name', 'customEnvKey'), hasEntry ('value','customEnvValue')))))
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomShell() {
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
containerShell: '/busybox/sh'
|
|
) {
|
|
//nothing to exeute
|
|
}
|
|
assertThat(containerShell, is('/busybox/sh'))
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomContainerCommand() {
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
containerCommand: '/busybox/tail -f /dev/null'
|
|
) {
|
|
//nothing to exeute
|
|
}
|
|
assertThat(containerCommands, hasItem(['/bin/sh', '-c', '/busybox/tail -f /dev/null']))
|
|
}
|
|
|
|
@Test
|
|
void testSkipDockerImagePull() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
dockerPullImage: false,
|
|
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute']
|
|
) {
|
|
container(name: 'mavenexecute') {
|
|
bodyExecuted = true
|
|
}
|
|
}
|
|
assertEquals(false, pullImageMap.get('maven:3.5-jdk-8-alpine'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testSkipSidecarImagePull() throws Exception {
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
containerCommands: ['selenium/standalone-chrome': ''],
|
|
containerEnvVars: [
|
|
'selenium/standalone-chrome': ['customEnvKey': 'customEnvValue']
|
|
],
|
|
containerMap: [
|
|
'maven:3.5-jdk-8-alpine': 'mavenexecute',
|
|
'selenium/standalone-chrome': 'selenium'
|
|
],
|
|
containerName: 'mavenexecute',
|
|
containerWorkspaces: [
|
|
'selenium/standalone-chrome': ''
|
|
],
|
|
containerPullImageFlags: [
|
|
'maven:3.5-jdk-8-alpine': true,
|
|
'selenium/standalone-chrome': false
|
|
],
|
|
dockerWorkspace: '/home/piper'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertEquals(true, pullImageMap.get('maven:3.5-jdk-8-alpine'))
|
|
assertEquals(false, pullImageMap.get('selenium/standalone-chrome'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithCustomNamespace() {
|
|
def expectedNamespace = "sandbox"
|
|
nullScript.commonPipelineEnvironment.configuration = [general: [jenkinsKubernetes: [namespace: expectedNamespace]]]
|
|
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
) { bodyExecuted = true }
|
|
assertTrue(bodyExecuted)
|
|
assertThat(namespace, is(equalTo(expectedNamespace)))
|
|
}
|
|
|
|
@Test
|
|
void testDockerExecuteOnKubernetesWithSecurityContext() {
|
|
def expectedSecurityContext = [ runAsUser: 1000, fsGroup: 1000 ]
|
|
nullScript.commonPipelineEnvironment.configuration = [general: [jenkinsKubernetes: [
|
|
securityContext: expectedSecurityContext]]]
|
|
|
|
stepRule.step.dockerExecuteOnKubernetes(
|
|
script: nullScript,
|
|
juStabUtils: utils,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
) { bodyExecuted = true }
|
|
assertTrue(bodyExecuted)
|
|
assertThat(securityContext, is(equalTo(expectedSecurityContext)))
|
|
}
|
|
|
|
|
|
private container(options, body) {
|
|
containerName = options.name
|
|
containerShell = options.shell
|
|
body()
|
|
}
|
|
}
|