mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
b7468a7ae4
Having the step name always the same like the file name, which is in turn the class name is redundant.
227 lines
8.8 KiB
Groovy
227 lines
8.8 KiB
Groovy
import static com.sap.piper.Prerequisites.checkScript
|
|
|
|
import com.cloudbees.groovy.cps.NonCPS
|
|
|
|
import com.sap.piper.ConfigurationHelper
|
|
import com.sap.piper.JenkinsUtils
|
|
import com.sap.piper.Utils
|
|
import com.sap.piper.k8s.ContainerMap
|
|
|
|
import groovy.transform.Field
|
|
|
|
@Field def STEP_NAME = getClass().getName()
|
|
@Field def PLUGIN_ID_DOCKER_WORKFLOW = 'docker-workflow'
|
|
|
|
@Field Set GENERAL_CONFIG_KEYS = ['jenkinsKubernetes']
|
|
|
|
@Field Set PARAMETER_KEYS = [
|
|
'containerPortMappings',
|
|
'dockerEnvVars',
|
|
'dockerImage',
|
|
'dockerName',
|
|
'dockerOptions',
|
|
'dockerWorkspace',
|
|
'dockerVolumeBind',
|
|
'sidecarEnvVars',
|
|
'sidecarImage',
|
|
'sidecarName',
|
|
'sidecarOptions',
|
|
'sidecarWorkspace',
|
|
'sidecarVolumeBind',
|
|
'stashContent'
|
|
]
|
|
@Field Set STEP_CONFIG_KEYS = PARAMETER_KEYS
|
|
|
|
void call(Map parameters = [:], body) {
|
|
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
|
|
|
final script = checkScript(this, parameters) ?: this
|
|
|
|
def utils = parameters?.juStabUtils ?: new Utils()
|
|
|
|
Map config = ConfigurationHelper.newInstance(this)
|
|
.loadStepDefaults()
|
|
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
|
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
|
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
|
.mixin(parameters, PARAMETER_KEYS)
|
|
.use()
|
|
if (isKubernetes() && config.dockerImage) {
|
|
if (env.POD_NAME && isContainerDefined(config)) {
|
|
container(getContainerDefined(config)) {
|
|
echo "[INFO][${STEP_NAME}] Executing inside a Kubernetes Container."
|
|
body()
|
|
sh "chown -R 1000:1000 ."
|
|
}
|
|
} else {
|
|
if (!config.sidecarImage) {
|
|
dockerExecuteOnKubernetes(
|
|
script: script,
|
|
dockerImage: config.dockerImage,
|
|
dockerEnvVars: config.dockerEnvVars,
|
|
dockerWorkspace: config.dockerWorkspace,
|
|
stashContent: config.stashContent
|
|
){
|
|
echo "[INFO][${STEP_NAME}] Executing inside a Kubernetes Pod"
|
|
body()
|
|
}
|
|
} else {
|
|
Map paramMap = [
|
|
script: script,
|
|
containerCommands: [:],
|
|
containerEnvVars: [:],
|
|
containerMap: [:],
|
|
containerName: config.dockerName,
|
|
containerPortMappings: [:],
|
|
containerWorkspaces: [:],
|
|
stashContent: config.stashContent
|
|
]
|
|
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 {
|
|
boolean executeInsideDocker = true
|
|
if (!JenkinsUtils.isPluginActive(PLUGIN_ID_DOCKER_WORKFLOW)) {
|
|
echo "[WARNING][${STEP_NAME}] Docker not supported. Plugin '${PLUGIN_ID_DOCKER_WORKFLOW}' is not installed or not active. Configured docker image '${config.dockerImage}' will not be used."
|
|
executeInsideDocker = false
|
|
}
|
|
|
|
def returnCode = sh script: 'which docker > /dev/null', returnStatus: true
|
|
if (returnCode != 0) {
|
|
echo "[WARNING][${STEP_NAME}] No docker environment found (command 'which docker' did not return with '0'). Configured docker image '${config.dockerImage}' will not be used."
|
|
executeInsideDocker = false
|
|
}
|
|
|
|
returnCode = sh script: 'docker ps -q > /dev/null', returnStatus: true
|
|
if (returnCode != 0) {
|
|
echo "[WARNING][$STEP_NAME] Cannot connect to docker daemon (command 'docker ps' did not return with '0'). Configured docker image '${config.dockerImage}' will not be used."
|
|
executeInsideDocker = false
|
|
}
|
|
if (executeInsideDocker && config.dockerImage) {
|
|
utils.unstashAll(config.stashContent)
|
|
def image = docker.image(config.dockerImage)
|
|
image.pull()
|
|
if (!config.sidecarImage) {
|
|
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
|
body()
|
|
}
|
|
} else {
|
|
def networkName = "sidecar-${UUID.randomUUID()}"
|
|
sh "docker network create ${networkName}"
|
|
try{
|
|
def sidecarImage = docker.image(config.sidecarImage)
|
|
sidecarImage.pull()
|
|
config.sidecarOptions = config.sidecarOptions?:[]
|
|
if(config.sidecarName)
|
|
config.sidecarOptions.add("--network-alias ${config.sidecarName}")
|
|
config.sidecarOptions.add("--network ${networkName}")
|
|
sidecarImage.withRun(getDockerOptions(config.sidecarEnvVars, config.sidecarVolumeBind, config.sidecarOptions)) { c ->
|
|
config.dockerOptions = config.dockerOptions?:[]
|
|
if(config.dockerName)
|
|
config.dockerOptions.add("--network-alias ${config.dockerName}")
|
|
config.dockerOptions.add("--network ${networkName}")
|
|
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
|
echo "[INFO][${STEP_NAME}] Running with sidecar container."
|
|
body()
|
|
}
|
|
}
|
|
}finally{
|
|
sh "docker network remove ${networkName}"
|
|
}
|
|
}
|
|
} else {
|
|
echo "[INFO][${STEP_NAME}] Running on local environment."
|
|
body()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Returns a string with docker options containing
|
|
* environment variables (if set).
|
|
* Possible to extend with further options.
|
|
* @param dockerEnvVars Map with environment variables
|
|
*/
|
|
@NonCPS
|
|
private getDockerOptions(Map dockerEnvVars, Map dockerVolumeBind, def dockerOptions) {
|
|
def specialEnvironments = [
|
|
'http_proxy',
|
|
'https_proxy',
|
|
'no_proxy',
|
|
'HTTP_PROXY',
|
|
'HTTPS_PROXY',
|
|
'NO_PROXY'
|
|
]
|
|
def options = []
|
|
if (dockerEnvVars) {
|
|
for (String k : dockerEnvVars.keySet()) {
|
|
options.add("--env ${k}=${dockerEnvVars[k].toString()}")
|
|
}
|
|
}
|
|
|
|
for (String envVar : specialEnvironments) {
|
|
if (dockerEnvVars == null || !dockerEnvVars.containsKey(envVar)) {
|
|
options.add("--env ${envVar}")
|
|
}
|
|
}
|
|
|
|
if (dockerVolumeBind) {
|
|
for (String k : dockerVolumeBind.keySet()) {
|
|
options.add("--volume ${k}:${dockerVolumeBind[k].toString()}")
|
|
}
|
|
}
|
|
|
|
if (dockerOptions) {
|
|
if (dockerOptions instanceof CharSequence) {
|
|
options.add(dockerOptions.toString())
|
|
} else if (dockerOptions instanceof List) {
|
|
for (String option : dockerOptions) {
|
|
options.add "${option}"
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Unexpected type for dockerOptions. Expected was either a list or a string. Actual type was: '${dockerOptions.getClass()}'")
|
|
}
|
|
}
|
|
return options.join(' ')
|
|
}
|
|
|
|
|
|
boolean isContainerDefined(config) {
|
|
Map containerMap = ContainerMap.instance.getMap()
|
|
|
|
if (!containerMap.containsKey(env.POD_NAME)) {
|
|
return false
|
|
}
|
|
|
|
return containerMap.get(env.POD_NAME).containsKey(config.dockerImage)
|
|
}
|
|
|
|
|
|
def getContainerDefined(config) {
|
|
return ContainerMap.instance.getMap().get(env.POD_NAME).get(config.dockerImage).toLowerCase()
|
|
}
|
|
|
|
|
|
boolean isKubernetes() {
|
|
return Boolean.valueOf(env.ON_K8S)
|
|
}
|