mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
Merge branch 'master' into pr/swaPushOldConfigUsed
This commit is contained in:
commit
130fe6a941
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.idea/
|
||||
bin/
|
||||
.settings
|
||||
logs
|
||||
reports
|
||||
|
BIN
documentation/docs/images/k8s_env.png
Normal file
BIN
documentation/docs/images/k8s_env.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
@ -8,26 +8,67 @@ Proxy environment variables defined on the Jenkins machine are also available in
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| -------------------|-----------|-----------------------------------|----------------------------|
|
||||
| `script` | no | empty `globalPipelineEnvironment` | |
|
||||
| `dockerImage` | no | '' | |
|
||||
| `dockerEnvVars` | no | [:] | |
|
||||
| `dockerOptions` | no | '' | |
|
||||
| `dockerVolumeBind` | no | [:] | |
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|containerPortMappings|no|||
|
||||
|dockerEnvVars|no|`[:]`||
|
||||
|dockerImage|no|`''`||
|
||||
|dockerName|no|||
|
||||
|dockerOptions|no|`''`||
|
||||
|dockerVolumeBind|no|`[:]`||
|
||||
|dockerWorkspace|no|||
|
||||
|jenkinsKubernetes|no|`[jnlpAgent:s4sdk/jenkins-agent-k8s:latest]`||
|
||||
|sidecarEnvVars|no|||
|
||||
|sidecarImage|no|||
|
||||
|sidecarName|no|||
|
||||
|sidecarOptions|no|||
|
||||
|sidecarVolumeBind|no|||
|
||||
|sidecarWorkspace|no|||
|
||||
|
||||
* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
|
||||
* `dockerImage` Name of the docker image that should be used. If empty, Docker is not used.
|
||||
* `dockerEnvVars` Environment variables to set in the container, e.g. [http_proxy:'proxy:8080']
|
||||
* `containerPortMappings`: Map which defines per docker image the port mappings, like `containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]`
|
||||
* `dockerEnvVars`: Environment variables to set in the container, e.g. [http_proxy:'proxy:8080']
|
||||
* `dockerImage`: Name of the docker image that should be used. If empty, Docker is not used and the command is executed directly on the Jenkins system.
|
||||
* `dockerName`: only relevant for Kubernetes case: Name of the container launching `dockerImage`
|
||||
* `dockerOptions` Docker options to be set when starting the container. It can be a list or a string.
|
||||
* `dockerVolumeBind` Volumes that should be mounted into the container.
|
||||
* `dockerWorkspace`: only relevant for Kubernetes case: specifies a dedicated user home directory for the container which will be passed as value for environment variable `HOME`
|
||||
* `sidecarEnvVars` defines environment variables for the sidecar container, similar to `dockerEnvVars`
|
||||
* `sidecarImage`: Name of the docker image of the sidecar container. Do not provide this value if no sidecar container is required.
|
||||
* `sidecarName`: as `dockerName` for the sidecar container
|
||||
* `sidecarOptions`: as `dockerOptions` for the sidecar container
|
||||
* `sidecarVolumeBind`: as `dockerVolumeBind` for the sidecar container
|
||||
* `sidecarWorkspace`: as `dockerWorkspace` for the sidecar container
|
||||
|
||||
|
||||
## Kubernetes support
|
||||
If the Jenkins is setup on a Kubernetes cluster, then you can execute the closure inside a container of a pod by setting an environment variable `ON_K8S` to `true`. However, it will ignore both `dockeOptions` and `dockerVolumeBind` values.
|
||||
If the Jenkins is setup on a Kubernetes cluster, then you can execute the closure inside a container of a pod by setting an environment variable `ON_K8S` to `true`. However, it will ignore `containerPortMappings`, `dockerOptions` and `dockerVolumeBind` values.
|
||||
|
||||
## Step configuration
|
||||
none
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|containerPortMappings||X|X|
|
||||
|dockerEnvVars||X|X|
|
||||
|dockerImage||X|X|
|
||||
|dockerName||X|X|
|
||||
|dockerOptions||X|X|
|
||||
|dockerVolumeBind||X|X|
|
||||
|dockerWorkspace||X|X|
|
||||
|jenkinsKubernetes|X|||
|
||||
|sidecarEnvVars||X|X|
|
||||
|sidecarImage||X|X|
|
||||
|sidecarName||X|X|
|
||||
|sidecarOptions||X|X|
|
||||
|sidecarVolumeBind||X|X|
|
||||
|sidecarWorkspace||X|X|
|
||||
|
||||
|
||||
## Return value
|
||||
none
|
||||
@ -60,6 +101,25 @@ dockerExecute(script: this, dockerImage: 'maven:3.5-jdk-7'){
|
||||
|
||||
In the above example, the `dockerEcecute` step will internally invoke [dockerExecuteOnKubernetes](dockerExecuteOnKubernetes.md) step and execute the closure inside a pod.
|
||||
|
||||
## Example 3: Run closure inside a container which is attached to a sidecar container (as for example used in [seleniumExecuteTests](seleniumExecuteTests.md):
|
||||
|
||||
```groovy
|
||||
dockerExecute(
|
||||
script: script,
|
||||
containerPortMappings: [containerPortMappings:'selenium/standalone-chrome':[containerPort: 4444, hostPort: 4444]],
|
||||
dockerImage: 'node:8-stretch',
|
||||
dockerName: 'node',
|
||||
dockerWorkspace: '/home/node',
|
||||
sidecarImage: 'selenium/standalone-chrome',
|
||||
sidecarName: 'selenium',
|
||||
) {
|
||||
git url: 'https://github.wdf.sap.corp/XXXXX/WebDriverIOTest.git'
|
||||
sh '''npm install
|
||||
node index.js
|
||||
'''
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,27 +6,62 @@ Executes a closure inside a container in a kubernetes pod. Proxy environment var
|
||||
|
||||
## Prerequisites
|
||||
* The Jenkins should be running on kubernetes.
|
||||
* An environment variable `ON_K8S` should be created on Jenkins and initialized to `true`.
|
||||
* An environment variable `ON_K8S` should be created on Jenkins and initialized to `true`. This could for example be done via _Jenkins_ - _Manage Jenkins_ - _Configure System_ - _Global properties_ - _Environment variables_
|
||||
|
||||
![Jenkins environment variable configuration](../images/k8s_env.png)
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| -------------------|-----------|-----------------------------------|----------------------------|
|
||||
| `script` | no | empty `globalPipelineEnvironment` | |
|
||||
| `dockerImage` | yes | | |
|
||||
| `dockerEnvVars` | no | [:] | |
|
||||
| `dockerWorkspace` | no | '' | |
|
||||
| `containerMap` | no | [:] | |
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|containerCommands|no|||
|
||||
|containerEnvVars|no|||
|
||||
|containerMap|no|`[:]`||
|
||||
|containerName|no|||
|
||||
|containerPortMappings|no|||
|
||||
|containerWorkspaces|no|||
|
||||
|dockerEnvVars|no|`[:]`||
|
||||
|dockerImage|yes|||
|
||||
|dockerWorkspace|no|`''`||
|
||||
|jenkinsKubernetes|no|`[jnlpAgent:s4sdk/jenkins-agent-k8s:latest]`||
|
||||
|stashExcludes|no|`[workspace:nohup.out]`||
|
||||
|stashIncludes|no|`[workspace:**/*.*]`||
|
||||
|
||||
* `script` defines the global script environment of the Jenkins file run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
|
||||
* `containerCommands` specifies start command for containers to overwrite Piper default (`/usr/bin/tail -f /dev/null`). If container's defaultstart command should be used provide empty string like: `['selenium/standalone-chrome': '']`.
|
||||
* `containerEnvVars` specifies environment variables per container. If not provided `dockerEnvVars` will be used.
|
||||
* `containerMap` A map of docker image to the name of the container. The pod will be created with all the images from this map and they are labled based on the value field of each map entry.
|
||||
Example: `['maven:3.5-jdk-8-alpine': 'mavenExecute', 'selenium/standalone-chrome': 'selenium', 'famiko/jmeter-base': 'checkJMeter', 's4sdk/docker-cf-cli': 'cloudfoundry']`
|
||||
|
||||
* `containerName`: optional configuration in combination with containerMap to define the container where the commands should be executed in
|
||||
* `containerPortMappings`: Map which defines per docker image the port mappings, like `containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]`
|
||||
* `containerWorkspaces` specifies workspace (=home directory of user) per container. If not provided `dockerWorkspace` will be used. If empty, home directory will not be set.
|
||||
* `dockerImage` Name of the docker image that should be used. If empty, Docker is not used.
|
||||
* `dockerEnvVars` Environment variables to set in the container, e.g. [http_proxy:'proxy:8080']
|
||||
* `dockerWorkspace` Docker options to be set when starting the container. It can be a list or a string.
|
||||
* `containerMap` A map of docker image to the name of the container. The pod will be created with all the images from this map and they are labled based on the value field of each map entry.
|
||||
Ex `['maven:3.5-jdk-8-alpine': 'mavenExecute', 'famiko/jmeter-base': 'checkJMeter', 's4sdk/docker-cf-cli': 'cloudfoundry']`
|
||||
|
||||
## Step configuration
|
||||
none
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|containerCommands||X|X|
|
||||
|containerEnvVars||X|X|
|
||||
|containerMap||X|X|
|
||||
|containerName||X|X|
|
||||
|containerPortMappings||X|X|
|
||||
|containerWorkspaces||X|X|
|
||||
|dockerEnvVars||X|X|
|
||||
|dockerImage||X|X|
|
||||
|dockerWorkspace||X|X|
|
||||
|jenkinsKubernetes|X|||
|
||||
|stashExcludes||X|X|
|
||||
|stashIncludes||X|X|
|
||||
|
||||
## Return value
|
||||
none
|
||||
@ -70,5 +105,23 @@ dockerExecuteOnKubernetes(script: script, containerMap: ['maven:3.5-jdk-8-alpine
|
||||
|
||||
In the above example, a pod will be created with multiple Docker containers that are passed as a `containerMap`. The containers can be chosen for executing by referring their labels as shown in the example.
|
||||
|
||||
## Example 3: Running a closure in a dedicated container of a multi-container pod
|
||||
|
||||
```sh
|
||||
# set environment variable
|
||||
export ON_K8S=true"
|
||||
```
|
||||
|
||||
```groovy
|
||||
dockerExecuteOnKubernetes(
|
||||
script: script,
|
||||
containerCommands: ['selenium/standalone-chrome': ''],
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'maven', 'selenium/standalone-chrome': 'selenium'],
|
||||
containerName: 'maven',
|
||||
containerPortMappings: ['selenium/standalone-chrome': [containerPort: 4444, hostPort: 4444]]
|
||||
containerWorkspaces: ['selenium/standalone-chrome': '']
|
||||
){
|
||||
echo "Executing inside a Kubernetes Pod inside 'maven' container to run Selenium tests"
|
||||
sh "mvn clean install"
|
||||
}
|
||||
```
|
||||
|
137
documentation/docs/steps/seleniumExecuteTests.md
Normal file
137
documentation/docs/steps/seleniumExecuteTests.md
Normal file
@ -0,0 +1,137 @@
|
||||
# seleniumExecuteTests
|
||||
|
||||
## Description
|
||||
|
||||
Enables UI test execution with Selenium in a sidecar container.
|
||||
|
||||
The step executes a closure (see example below) connecting to a sidecar container with a Selenium Server.
|
||||
|
||||
When executing in a
|
||||
* local Docker environment, please make sure to set Selenium host to **`selenium`** in your tests.
|
||||
* Kubernetes environment, plese make sure to set Seleniums host to **`localhost`** in your tests.
|
||||
|
||||
!!! note "Proxy Environments"
|
||||
If work in an environment containing a proxy, please make sure that `localhost`/`selenium` is added to your proxy exclusion list, e.g. via environment variable `NO_PROXY` & `no_proxy`. You can pass those via parameters `dockerEnvVars` and `sidecarEnvVars` directly to the containers if required.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
none
|
||||
|
||||
## Example
|
||||
|
||||
```groovy
|
||||
seleniumExecuteTests (script: this) {
|
||||
git url: 'https://github.wdf.sap.corp/xxxxx/WebDriverIOTest.git'
|
||||
sh '''npm install
|
||||
node index.js'''
|
||||
}
|
||||
```
|
||||
|
||||
### Example test using WebdriverIO
|
||||
|
||||
Example based on http://webdriver.io/guide/getstarted/modes.html and http://webdriver.io/guide.html
|
||||
|
||||
#### Configuration for Local Docker Environment
|
||||
```
|
||||
var webdriverio = require('webdriverio');
|
||||
var options = {
|
||||
host: 'selenium',
|
||||
port: 4444,
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome'
|
||||
}
|
||||
};
|
||||
```
|
||||
#### Configuration for Kubernetes Environment
|
||||
```
|
||||
var webdriverio = require('webdriverio');
|
||||
var options = {
|
||||
host: 'localhost',
|
||||
port: 4444,
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Test Code (index.js)
|
||||
|
||||
```
|
||||
// ToDo: add configuration from above
|
||||
|
||||
webdriverio
|
||||
.remote(options)
|
||||
.init()
|
||||
.url('http://www.google.com')
|
||||
.getTitle().then(function(title) {
|
||||
console.log('Title was: ' + title);
|
||||
})
|
||||
.end()
|
||||
.catch(function(err) {
|
||||
console.log(err);
|
||||
});
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|containerPortMappings|no|`[selenium/standalone-chrome:[[containerPort:4444, hostPort:4444]]]`||
|
||||
|dockerImage|no|buildTool=`maven`: `maven:3.5-jdk-7`<br />buildTool=`npm`: `node:8-stretch`<br />||
|
||||
|dockerName|no|buildTool=`maven`: `maven`<br />buildTool=`npm`: `npm`<br />||
|
||||
|dockerWorkspace|no|buildTool=`maven`: ``<br />buildTool=`npm`: `/home/node`<br />||
|
||||
|failOnError|no|`true`||
|
||||
|gitBranch|no|||
|
||||
|gitSshKeyCredentialsId|no|``||
|
||||
|sidecarEnvVars|no|||
|
||||
|sidecarImage|no|`selenium/standalone-chrome`||
|
||||
|sidecarName|no|`selenium`||
|
||||
|sidecarVolumeBind|no|`[/dev/shm:/dev/shm]`||
|
||||
|stashContent|no|<ul><li>`tests`</li></ul>||
|
||||
|testRepository|no|||
|
||||
|
||||
* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
|
||||
* `containerPortMappings`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerImage`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerName`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerWorkspace`, see step [dockerExecute](dockerExecute.md)
|
||||
* `failOnError` specifies if the step should fail in case the execution of the body of this step fails.
|
||||
* `sidecarEnvVars`, see step [dockerExecute](dockerExecute.md)
|
||||
* `sidecarImage`, see step [dockerExecute](dockerExecute.md)
|
||||
* `sidecarName`, see step [dockerExecute](dockerExecute.md)
|
||||
* `sidecarVolumeBind`, see step [dockerExecute](dockerExecute.md)
|
||||
* If specific stashes should be considered for the tests, you can pass this via parameter `stashContent`
|
||||
* In case the test implementation is stored in a different repository than the code itself, you can define the repository containing the tests using parameter `testRepository` and if required `gitBranch` (for a different branch than master) and `gitSshKeyCredentialsId` (for protected repositories). For protected repositories the testRepository needs to contain the ssh git url.
|
||||
|
||||
## Step configuration
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|containerPortMappings|X|X|X|
|
||||
|dockerImage|X|X|X|
|
||||
|dockerName|X|X|X|
|
||||
|dockerWorkspace|X|X|X|
|
||||
|failOnError|X|X|X|
|
||||
|gitBranch|X|X|X|
|
||||
|gitSshKeyCredentialsId|X|X|X|
|
||||
|sidecarEnvVars|X|X|X|
|
||||
|sidecarImage|X|X|X|
|
||||
|sidecarName|X|X|X|
|
||||
|sidecarVolumeBind|X|X|X|
|
||||
|stashContent|X|X|X|
|
||||
|testRepository|X|X|X|
|
||||
|
||||
## Return value
|
||||
none
|
||||
|
||||
## Side effects
|
||||
none
|
||||
|
||||
## Exceptions
|
||||
none
|
@ -19,6 +19,7 @@ nav:
|
||||
- pipelineExecute: steps/pipelineExecute.md
|
||||
- pipelineStashFiles: steps/pipelineStashFiles.md
|
||||
- prepareDefaultValues: steps/prepareDefaultValues.md
|
||||
- seleniumExecuteTests: steps/seleniumExecuteTests.md
|
||||
- setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md
|
||||
- toolValidate: steps/toolValidate.md
|
||||
- transportRequestCreate: steps/transportRequestCreate.md
|
||||
|
2
pom.xml
2
pom.xml
@ -10,7 +10,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sap.cp.jenkins</groupId>
|
||||
<artifactId>jenkins-library</artifactId>
|
||||
<version>0.6</version>
|
||||
<version>0.7</version>
|
||||
|
||||
<name>SAP CP Piper Library</name>
|
||||
<description>Shared library containing steps and utilities to set up continuous deployment processes for SAP technologies.</description>
|
||||
|
@ -192,6 +192,28 @@ steps:
|
||||
pipelineConfigAndTests: ''
|
||||
securityDescriptor: ''
|
||||
tests: ''
|
||||
seleniumExecuteTests:
|
||||
buildTool: 'npm'
|
||||
containerPortMappings:
|
||||
'selenium/standalone-chrome':
|
||||
- containerPort: 4444
|
||||
hostPort: 4444
|
||||
dockerLinkAlias: 'selenium'
|
||||
failOnError: true
|
||||
sidecarImage: 'selenium/standalone-chrome'
|
||||
sidecarName: 'selenium'
|
||||
sidecarVolumeBind:
|
||||
'/dev/shm': '/dev/shm'
|
||||
stashContent:
|
||||
- 'tests'
|
||||
maven:
|
||||
dockerImage: 'maven:3.5-jdk-7'
|
||||
dockerName: 'maven'
|
||||
dockerWorkspace: ''
|
||||
npm:
|
||||
dockerImage: 'node:8-stretch'
|
||||
dockerName: 'npm'
|
||||
dockerWorkspace: '/home/node'
|
||||
snykExecute:
|
||||
buildDescriptorFile: './package.json'
|
||||
dockerImage: 'node:8-stretch'
|
||||
|
@ -16,6 +16,8 @@ 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
|
||||
@ -48,6 +50,8 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
def imageList = []
|
||||
def containerName = ''
|
||||
def envList = []
|
||||
def portList = []
|
||||
def containerCommands = []
|
||||
|
||||
|
||||
@Before
|
||||
@ -55,6 +59,8 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
containersList = []
|
||||
imageList = []
|
||||
envList = []
|
||||
portList = []
|
||||
containerCommands = []
|
||||
bodyExecuted = false
|
||||
JenkinsUtils.metaClass.static.isPluginActive = { def s -> new PluginMock(s).isActive() }
|
||||
helper.registerAllowedMethod('sh', [Map.class], {return whichDockerReturnValue})
|
||||
@ -67,6 +73,10 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
containersList.add(option.name)
|
||||
imageList.add(option.image)
|
||||
envList.add(option.envVars)
|
||||
portList.add(option.ports)
|
||||
if (option.command) {
|
||||
containerCommands.add(option.command)
|
||||
}
|
||||
}
|
||||
body()
|
||||
})
|
||||
@ -77,7 +87,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testRunOnPodNoContainerMapOnlyDockerImage() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerOptions: '-it',
|
||||
dockerVolumeBind: ['my_vol': '/my_vol'],
|
||||
@ -90,12 +100,13 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
assertTrue(envList.toString().contains('http://proxy:8000'))
|
||||
assertTrue(envList.toString().contains('/home/piper'))
|
||||
assertTrue(bodyExecuted)
|
||||
assertThat(containerCommands.size(), is(1))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesWithCustomContainerMap() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute']) {
|
||||
container(name: 'mavenexecute') {
|
||||
bodyExecuted = true
|
||||
@ -105,12 +116,13 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
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']]]
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute']) {
|
||||
container(name: 'mavenexecute') {
|
||||
bodyExecuted = true
|
||||
@ -127,7 +139,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesWithCustomJnlpWithDockerImage() throws Exception {
|
||||
nullScript.commonPipelineEnvironment.configuration = ['general': ['jenkinsKubernetes': ['jnlpAgent': 'myJnalpAgent']]]
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine') {
|
||||
bodyExecuted = true
|
||||
}
|
||||
@ -141,7 +153,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesWithCustomWorkspace() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute'],
|
||||
dockerWorkspace: '/home/piper') {
|
||||
container(name: 'mavenexecute') {
|
||||
@ -154,7 +166,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesWithCustomEnv() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute'],
|
||||
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
||||
container(name: 'mavenexecute') {
|
||||
@ -167,7 +179,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesUpperCaseContainerName() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: ['maven:3.5-jdk-8-alpine': 'MAVENEXECUTE'],
|
||||
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
||||
container(name: 'mavenexecute') {
|
||||
@ -183,7 +195,7 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
@Test
|
||||
void testDockerExecuteOnKubernetesEmptyContainerMapNoDockerImage() throws Exception {
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecuteOnKubernetes(script: nullScript,
|
||||
containerMap: [:],
|
||||
dockerEnvVars: ['customEnvKey': 'customEnvValue']) {
|
||||
container(name: 'jnlp') {
|
||||
@ -193,6 +205,55 @@ class DockerExecuteOnKubernetesTest extends BasePiperTest {
|
||||
assertFalse(bodyExecuted)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSidecarDefault() {
|
||||
List portMapping = []
|
||||
helper.registerAllowedMethod('portMapping', [Map.class], {m ->
|
||||
portMapping.add(m)
|
||||
return m
|
||||
})
|
||||
jsr.step.dockerExecuteOnKubernetes(
|
||||
script: nullScript,
|
||||
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, hasItem(hasItem([name: 'selenium0', containerPort: 4444, hostPort: 4444])))
|
||||
assertThat(portMapping, hasItem([name: 'selenium0', containerPort: 4444, hostPort: 4444]))
|
||||
assertThat(containerCommands.size(), is(1))
|
||||
assertThat(envList, hasItem(hasItem(allOf(hasEntry('key', 'customEnvKey'), hasEntry ('value','customEnvValue')))))
|
||||
}
|
||||
|
||||
|
||||
private container(options, body) {
|
||||
containerName = options.name
|
||||
body()
|
||||
|
@ -13,6 +13,8 @@ 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
|
||||
@ -50,7 +52,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
})
|
||||
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
||||
ContainerMap.instance.setMap(['testpod': ['maven:3.5-jdk-8-alpine': 'mavenexec']])
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
||||
bodyExecuted = true
|
||||
@ -65,7 +67,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
||||
binding.setVariable('env', [ON_K8S: 'true'])
|
||||
ContainerMap.instance.setMap(['testpod': ['maven:3.5-jdk-8-alpine': 'mavenexec']])
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
||||
bodyExecuted = true
|
||||
@ -79,7 +81,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
||||
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
||||
ContainerMap.instance.setMap([:])
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
||||
bodyExecuted = true
|
||||
@ -93,7 +95,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
||||
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
||||
ContainerMap.instance.setMap(['testpod':[:]])
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
||||
bodyExecuted = true
|
||||
@ -104,7 +106,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerContainer() throws Exception {
|
||||
jsr.step.call(script: nullScript, dockerImage: 'maven:3.5-jdk-8-alpine') {
|
||||
jsr.step.dockerExecute(script: nullScript, dockerImage: 'maven:3.5-jdk-8-alpine') {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertEquals('maven:3.5-jdk-8-alpine', docker.getImageName())
|
||||
@ -115,7 +117,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerNoScript() throws Exception {
|
||||
jsr.step.call(dockerImage: 'maven:3.5-jdk-8-alpine') {
|
||||
jsr.step.dockerExecute(dockerImage: 'maven:3.5-jdk-8-alpine') {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertEquals('maven:3.5-jdk-8-alpine', docker.getImageName())
|
||||
@ -126,7 +128,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerContainerWithParameters() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerOptions: '-it',
|
||||
dockerVolumeBind: ['my_vol': '/my_vol'],
|
||||
@ -142,7 +144,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerContainerWithDockerOptionsList() throws Exception {
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerOptions: ['-it', '--network=my-network'],
|
||||
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
||||
@ -156,7 +158,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
@Test
|
||||
void testDockerNotInstalledResultsInLocalExecution() throws Exception {
|
||||
whichDockerReturnValue = 1
|
||||
jsr.step.call(script: nullScript,
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
dockerOptions: '-it') {
|
||||
bodyExecuted = true
|
||||
}
|
||||
@ -166,10 +168,70 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
assertFalse(docker.isImagePulled())
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSidecarDefault(){
|
||||
jsr.step.dockerExecute(
|
||||
script: nullScript,
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
sidecarEnvVars: ['testEnv':'testVal'],
|
||||
sidecarImage: 'selenium/standalone-chrome',
|
||||
sidecarVolumeBind: ['/dev/shm':'/dev/shm'],
|
||||
sidecarName: 'testAlias',
|
||||
sidecarPorts: ['4444':'4444', '1111':'1111']
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(docker.imagePullCount, is(2))
|
||||
assertThat(docker.sidecarParameters, allOf(
|
||||
containsString('--env testEnv=testVal'),
|
||||
containsString('--volume /dev/shm:/dev/shm')
|
||||
))
|
||||
assertThat(docker.parameters, containsString('--link uniqueId:testAlias'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSidecarKubernetes(){
|
||||
boolean dockerExecuteOnKubernetesCalled = false
|
||||
binding.setVariable('env', [ON_K8S: 'true'])
|
||||
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { params, body ->
|
||||
dockerExecuteOnKubernetesCalled = true
|
||||
assertThat(params.containerCommands['selenium/standalone-chrome'], is(''))
|
||||
assertThat(params.containerEnvVars, allOf(hasEntry('selenium/standalone-chrome', ['testEnv': 'testVal']),hasEntry('maven:3.5-jdk-8-alpine', null)))
|
||||
assertThat(params.containerMap, allOf(hasEntry('maven:3.5-jdk-8-alpine', 'maven'), hasEntry('selenium/standalone-chrome', 'selenium')))
|
||||
assertThat(params.containerName, is('maven'))
|
||||
assertThat(params.containerPortMappings['selenium/standalone-chrome'], hasItem(allOf(hasEntry('containerPort', 4444), hasEntry('hostPort', 4444))))
|
||||
assertThat(params.containerWorkspaces['maven:3.5-jdk-8-alpine'], is('/home/piper'))
|
||||
assertThat(params.containerWorkspaces['selenium/standalone-chrome'], is(''))
|
||||
body()
|
||||
})
|
||||
jsr.step.dockerExecute(
|
||||
script: nullScript,
|
||||
containerPortMappings: [
|
||||
'selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]
|
||||
],
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
dockerName: 'maven',
|
||||
dockerWorkspace: '/home/piper',
|
||||
sidecarEnvVars: ['testEnv':'testVal'],
|
||||
sidecarImage: 'selenium/standalone-chrome',
|
||||
sidecarName: 'selenium',
|
||||
sidecarVolumeBind: ['/dev/shm':'/dev/shm'],
|
||||
dockerLinkAlias: 'testAlias',
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(dockerExecuteOnKubernetesCalled, is(true))
|
||||
}
|
||||
|
||||
private class DockerMock {
|
||||
private String imageName
|
||||
private boolean imagePulled = false
|
||||
private int imagePullCount = 0
|
||||
private String parameters
|
||||
private String sidecarParameters
|
||||
|
||||
DockerMock image(String imageName) {
|
||||
this.imageName = imageName
|
||||
@ -177,6 +239,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
void pull() {
|
||||
imagePullCount++
|
||||
imagePulled = true
|
||||
}
|
||||
|
||||
@ -185,6 +248,11 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
body()
|
||||
}
|
||||
|
||||
void withRun(String parameters, body) {
|
||||
this.sidecarParameters = parameters
|
||||
body([id: 'uniqueId'])
|
||||
}
|
||||
|
||||
String getImageName() {
|
||||
return imageName
|
||||
}
|
||||
|
98
test/groovy/SeleniumExecuteTestsTest.groovy
Normal file
98
test/groovy/SeleniumExecuteTestsTest.groovy
Normal file
@ -0,0 +1,98 @@
|
||||
import hudson.AbortException
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class SeleniumExecuteTestsTest extends BasePiperTest {
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
|
||||
private JenkinsDockerExecuteRule jedr = new JenkinsDockerExecuteRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(thrown)
|
||||
.around(jedr)
|
||||
.around(jsr) // needs to be activated after jedr, otherwise executeDocker is not mocked
|
||||
|
||||
boolean bodyExecuted = false
|
||||
|
||||
def gitMap
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
bodyExecuted = false
|
||||
helper.registerAllowedMethod('git', [Map.class], {m ->
|
||||
gitMap = m
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteSeleniumDefault() {
|
||||
jsr.step.seleniumExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(jedr.dockerParams.containerPortMappings, is(['selenium/standalone-chrome': [[containerPort: 4444, hostPort: 4444]]]))
|
||||
assertThat(jedr.dockerParams.dockerImage, is('node:8-stretch'))
|
||||
assertThat(jedr.dockerParams.dockerName, is('npm'))
|
||||
assertThat(jedr.dockerParams.dockerWorkspace, is('/home/node'))
|
||||
assertThat(jedr.dockerParams.sidecarEnvVars, is(null))
|
||||
assertThat(jedr.dockerParams.sidecarImage, is('selenium/standalone-chrome'))
|
||||
assertThat(jedr.dockerParams.sidecarName, is('selenium'))
|
||||
assertThat(jedr.dockerParams.sidecarVolumeBind, is(['/dev/shm': '/dev/shm']))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteSeleniumError() {
|
||||
thrown.expectMessage('Error occured')
|
||||
jsr.step.seleniumExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils
|
||||
) {
|
||||
throw new AbortException('Error occured')
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteSeleniumIgnoreError() {
|
||||
jsr.step.seleniumExecuteTests(
|
||||
script: nullScript,
|
||||
failOnError: false,
|
||||
juStabUtils: utils
|
||||
) {
|
||||
bodyExecuted = true
|
||||
throw new AbortException('Error occured')
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteSeleniumCustomRepo() {
|
||||
jsr.step.seleniumExecuteTests(
|
||||
script: nullScript,
|
||||
gitBranch: 'test',
|
||||
gitSshKeyCredentialsId: 'testCredentials',
|
||||
juStabUtils: utils,
|
||||
testRepository: 'git@test/test.git'
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(gitMap, hasEntry('branch', 'test'))
|
||||
assertThat(gitMap, hasEntry('credentialsId', 'testCredentials'))
|
||||
assertThat(gitMap, hasEntry('url', 'git@test/test.git'))
|
||||
}
|
||||
}
|
@ -9,11 +9,21 @@ import groovy.transform.Field
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['jenkinsKubernetes']
|
||||
|
||||
@Field Set PARAMETER_KEYS = ['dockerImage',
|
||||
'dockerOptions',
|
||||
'dockerWorkspace',
|
||||
'dockerEnvVars',
|
||||
'dockerVolumeBind']
|
||||
@Field Set PARAMETER_KEYS = [
|
||||
'containerPortMappings',
|
||||
'dockerEnvVars',
|
||||
'dockerImage',
|
||||
'dockerName',
|
||||
'dockerOptions',
|
||||
'dockerWorkspace',
|
||||
'dockerVolumeBind',
|
||||
'sidecarName',
|
||||
'sidecarEnvVars',
|
||||
'sidecarImage',
|
||||
'sidecarOptions',
|
||||
'sidecarWorkspace',
|
||||
'sidecarVolumeBind'
|
||||
]
|
||||
@Field Set STEP_CONFIG_KEYS = PARAMETER_KEYS
|
||||
|
||||
void call(Map parameters = [:], body) {
|
||||
@ -31,19 +41,48 @@ void call(Map parameters = [:], body) {
|
||||
if (isKubernetes() && config.dockerImage) {
|
||||
if (env.POD_NAME && isContainerDefined(config)) {
|
||||
container(getContainerDefined(config)) {
|
||||
echo "Executing inside a Kubernetes Container"
|
||||
echo "[INFO][${STEP_NAME}] Executing inside a Kubernetes Container."
|
||||
body()
|
||||
sh "chown -R 1000:1000 ."
|
||||
}
|
||||
} else {
|
||||
dockerExecuteOnKubernetes(
|
||||
script: script,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerEnvVars: config.dockerEnvVars,
|
||||
dockerWorkspace: config.dockerWorkspace
|
||||
){
|
||||
echo "Executing inside a Kubernetes Pod"
|
||||
body()
|
||||
if (!config.sidecarImage) {
|
||||
dockerExecuteOnKubernetes(
|
||||
script: script,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerEnvVars: config.dockerEnvVars,
|
||||
dockerWorkspace: config.dockerWorkspace
|
||||
){
|
||||
echo "[INFO][${STEP_NAME}] Executing inside a Kubernetes Pod"
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
Map paramMap = [
|
||||
script: script,
|
||||
containerCommands: [:],
|
||||
containerEnvVars: [:],
|
||||
containerMap: [:],
|
||||
containerName: config.dockerName,
|
||||
containerPortMappings: [:],
|
||||
containerWorkspaces: [:]
|
||||
]
|
||||
paramMap.containerCommands[config.sidecarImage] = ''
|
||||
|
||||
paramMap.containerEnvVars[config.dockerImage] = config.dockerEnvVars
|
||||
paramMap.containerEnvVars[config.sidecarImage] = config.sidecarEnvVars
|
||||
|
||||
paramMap.containerMap[config.dockerImage] = config.dockerName
|
||||
paramMap.containerMap[config.sidecarImage] = config.sidecarName
|
||||
|
||||
paramMap.containerPortMappings = config.containerPortMappings
|
||||
|
||||
paramMap.containerWorkspaces[config.dockerImage] = config.dockerWorkspace
|
||||
paramMap.containerWorkspaces[config.sidecarImage] = ''
|
||||
|
||||
dockerExecuteOnKubernetes(paramMap){
|
||||
echo "[INFO][${STEP_NAME}] Executing inside a Kubernetes Pod with sidecar container"
|
||||
body()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -67,8 +106,21 @@ void call(Map parameters = [:], body) {
|
||||
if (executeInsideDocker && config.dockerImage) {
|
||||
def image = docker.image(config.dockerImage)
|
||||
image.pull()
|
||||
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
||||
body()
|
||||
if (!config.sidecarImage) {
|
||||
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
def sidecarImage = docker.image(config.sidecarImage)
|
||||
sidecarImage.pull()
|
||||
sidecarImage.withRun(getDockerOptions(config.sidecarEnvVars, config.sidecarVolumeBind, config.sidecarOptions)) { c ->
|
||||
config.dockerOptions = config.dockerOptions?:[]
|
||||
config.dockerOptions.add("--link ${c.id}:${config.sidecarName}")
|
||||
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
||||
echo "[INFO][${STEP_NAME}] Running with sidecar container."
|
||||
body()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "[INFO][${STEP_NAME}] Running on local environment."
|
||||
|
@ -7,10 +7,17 @@ import hudson.AbortException
|
||||
@Field def STEP_NAME = 'dockerExecuteOnKubernetes'
|
||||
@Field def PLUGIN_ID_KUBERNETES = 'kubernetes'
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['jenkinsKubernetes']
|
||||
@Field Set PARAMETER_KEYS = ['dockerImage',
|
||||
'dockerWorkspace',
|
||||
'dockerEnvVars',
|
||||
'containerMap']
|
||||
@Field Set PARAMETER_KEYS = [
|
||||
'containerCommands', //specify start command for containers to overwrite Piper default (`/usr/bin/tail -f /dev/null`). If container's defaultstart command should be used provide empty string like: `['selenium/standalone-chrome': '']`
|
||||
'containerEnvVars', //specify environment variables per container. If not provided dockerEnvVars will be used
|
||||
'containerMap', //specify multiple images which then form a kubernetes pod, example: containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute','selenium/standalone-chrome': 'selenium']
|
||||
'containerName', //optional configuration in combination with containerMap to define the container where the commands should be executed in
|
||||
'containerPortMappings', //map which defines per docker image the port mappings, like containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]
|
||||
'containerWorkspaces', //specify workspace (=home directory of user) per container. If not provided dockerWorkspace will be used. If empty, home directory will not be set.
|
||||
'dockerImage',
|
||||
'dockerWorkspace',
|
||||
'dockerEnvVars'
|
||||
]
|
||||
@Field Set STEP_CONFIG_KEYS = PARAMETER_KEYS.plus(['stashIncludes', 'stashExcludes'])
|
||||
|
||||
void call(Map parameters = [:], body) {
|
||||
@ -48,7 +55,14 @@ void executeOnPodWithCustomContainerList(Map parameters, body) {
|
||||
def config = parameters.config
|
||||
podTemplate(getOptions(config)) {
|
||||
node(config.uniqueId) {
|
||||
body()
|
||||
//allow execution in dedicated container
|
||||
if (config.containerName) {
|
||||
container(name: config.containerName){
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
body()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,9 +84,9 @@ void executeOnPodWithSingleContainer(Map parameters, body) {
|
||||
- The container method
|
||||
- The body
|
||||
* We use nested exception handling in this case.
|
||||
* In the first 2 cases, the workspace has not been modified. Hence, we can stash existing workspace as container and
|
||||
* unstash in the finally block. In case of exception thrown by the body, we need to stash the workspace from the container
|
||||
* in finally block
|
||||
* In the first 2 cases, the 'container' stash is not created because the inner try/finally is not reached.
|
||||
* However, the workspace has not been modified and don't need to be restored.
|
||||
* In case third case, we need to create the 'container' stash to bring the modified content back to the host.
|
||||
*/
|
||||
try {
|
||||
stashWorkspace(config, 'workspace')
|
||||
@ -84,13 +98,10 @@ void executeOnPodWithSingleContainer(Map parameters, body) {
|
||||
body()
|
||||
} finally {
|
||||
stashWorkspace(config, 'container')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
stashWorkspace(config, 'container')
|
||||
throw e
|
||||
} finally {
|
||||
unstashWorkspace(config, 'container')
|
||||
}
|
||||
@ -119,16 +130,35 @@ private void unstashWorkspace(config, prefix) {
|
||||
}
|
||||
|
||||
private List getContainerList(config) {
|
||||
def envVars = getContainerEnvs(config)
|
||||
|
||||
result = []
|
||||
result.push(containerTemplate(name: 'jnlp',
|
||||
image: config.jenkinsKubernetes.jnlpAgent))
|
||||
result.push(containerTemplate(
|
||||
name: 'jnlp',
|
||||
image: config.jenkinsKubernetes.jnlpAgent
|
||||
))
|
||||
config.containerMap.each { imageName, containerName ->
|
||||
result.push(containerTemplate(name: containerName.toLowerCase(),
|
||||
def templateParameters = [
|
||||
name: containerName.toLowerCase(),
|
||||
image: imageName,
|
||||
alwaysPullImage: true,
|
||||
command: '/usr/bin/tail -f /dev/null',
|
||||
envVars: envVars))
|
||||
envVars: getContainerEnvs(config, imageName)
|
||||
]
|
||||
|
||||
if (!config.containerCommands?.get(imageName)?.isEmpty()) {
|
||||
templateParameters.command = config.containerCommands?.get(imageName)?: '/usr/bin/tail -f /dev/null'
|
||||
}
|
||||
|
||||
if (config.containerPortMappings?.get(imageName)) {
|
||||
def ports = []
|
||||
def portCounter = 0
|
||||
config.containerPortMappings.get(imageName).each {mapping ->
|
||||
mapping.name = "${containerName}${portCounter}".toString()
|
||||
ports.add(portMapping(mapping))
|
||||
portCounter ++
|
||||
}
|
||||
templateParameters.ports = ports
|
||||
}
|
||||
result.push(containerTemplate(templateParameters))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -139,10 +169,10 @@ private List getContainerList(config) {
|
||||
* (Kubernetes-Plugin only!)
|
||||
* @param config Map with configurations
|
||||
*/
|
||||
private List getContainerEnvs(config) {
|
||||
private List getContainerEnvs(config, imageName) {
|
||||
def containerEnv = []
|
||||
def dockerEnvVars = config.dockerEnvVars ?: [:]
|
||||
def dockerWorkspace = config.dockerWorkspace ?: ''
|
||||
def dockerEnvVars = config.containerEnvVars?.get(imageName) ?: config.dockerEnvVars ?: [:]
|
||||
def dockerWorkspace = config.containerWorkspaces?.get(imageName) != null ? config.containerWorkspaces?.get(imageName) : config.dockerWorkspace ?: ''
|
||||
|
||||
if (dockerEnvVars) {
|
||||
for (String k : dockerEnvVars.keySet()) {
|
||||
|
73
vars/seleniumExecuteTests.groovy
Normal file
73
vars/seleniumExecuteTests.groovy
Normal file
@ -0,0 +1,73 @@
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.k8s.ContainerMap
|
||||
import groovy.transform.Field
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
|
||||
@Field String STEP_NAME = 'seleniumExecuteTests'
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'containerPortMappings', //port mappings required for containers. This will only take effect inside a Kubernetes pod, format [[containerPort: 1111, hostPort: 1111]]
|
||||
'dockerImage', //Docker image for code execution
|
||||
'dockerName', //name of the Docker container. This will only take effect inside a Kubernetes pod.
|
||||
'dockerWorkspace', //user home directory for Docker execution. This will only take effect inside a Kubernetes pod.
|
||||
'failOnError',
|
||||
'gitBranch', //only if testRepository is used: branch of testRepository. Default is master
|
||||
'gitSshKeyCredentialsId', //only if testRepository is used: ssh credentials id in case a protected testRepository is used
|
||||
'sidecarEnvVars', //envVars to be set in Selenium container if required
|
||||
'sidecarImage', //image for Selenium execution which runs as sidecar to dockerImage
|
||||
'sidecarName', //name of the Selenium container. If not on Kubernetes pod, this will define the name of the link to the Selenium container and is thus required for accessing the server, example http://selenium:4444 (default)
|
||||
'sidecarVolumeBind', //volume bind. This will not take effect in Kubernetes pod.
|
||||
'stashContent', //list of stash names which are required to be unstashed before test run
|
||||
'testRepository' //if tests are in a separate repository, git url can be defined. For protected repositories the git ssh url is required
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:], Closure body) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
def utils = parameters?.juStabUtils ?: new Utils()
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.dependingOn('buildTool').mixin('dockerImage')
|
||||
.dependingOn('buildTool').mixin('dockerName')
|
||||
.dependingOn('buildTool').mixin('dockerWorkspace')
|
||||
.use()
|
||||
|
||||
utils.pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
dockerExecute(
|
||||
script: script,
|
||||
containerPortMappings: config.containerPortMappings,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerName: config.dockerName,
|
||||
dockerWorkspace: config.dockerWorkspace,
|
||||
sidecarEnvVars: config.sidecarEnvVars,
|
||||
sidecarImage: config.sidecarImage,
|
||||
sidecarName: config.sidecarName,
|
||||
sidecarVolumeBind: config.sidecarVolumeBind
|
||||
) {
|
||||
try {
|
||||
if (config.testRepository) {
|
||||
def gitParameters = [url: config.testRepository]
|
||||
if (config.gitSshKeyCredentialsId) gitParameters.credentialsId = config.gitSshKeyCredentialsId
|
||||
if (config.gitBranch) gitParameters.branch = config.gitBranch
|
||||
git gitParameters
|
||||
} else {
|
||||
config.stashContent = utils.unstashAll(config.stashContent)
|
||||
}
|
||||
body()
|
||||
} catch (err) {
|
||||
if (config.failOnError) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user