How to run same job with different parameters in parallel using parallel[:] step - jenkins

I have a pipeline script that needs to trigger a "TEST" job.
The main parameter (string) is SETUP_DESCRIPTION which I phrase from a json file I'm creating.
Each server can have different amount of outputs depends on server resources (some have 2 setups and some 3).
Code looks like this:
#!/usr/bin/env groovy
import hudson.model.Result
import hudson.model.Run
import groovy.json.JsonSlurperClassic
import jenkins.model.CauseOfInterruption.UserInterruption
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
def projectProperties = [
buildDiscarder(
logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '14', numToKeepStr: '')
),
parameters([
string(defaultValue: '', description: '', name: 'SERVER_NAME'),
string(defaultValue: 'Ubuntu_17.10_x86_64_kvm', description: '', name: 'KVM_TEMPLATE'),
string(defaultValue: 'test#test.com'', description: 'mailing list', name: 'SW_MAIL'),
choice(choices: ['no', 'eth', 'ib'], description: '', name: 'SIMX_SERVER'),
choice(choices: ['cib', 'cx3pro', 'cx4', 'cx4lx', 'cx5', 'cx6'], description: '', name: 'SIMX_BOARD'),
choice(choices: ['os_install', 'provision', 'add_jks_slave', 'add_to_noga', 'tests'], description: '', name: 'RUN_STAGE')
]),
[$class: 'RebuildSettings', autoRebuild: false, rebuildDisabled: false],
[$class: 'ThrottleJobProperty',
categories: [],
limitOneJobWithMatchingParams: true,
maxConcurrentPerNode: 5,
maxConcurrentTotal: 5,
paramsToUseForLimit: '',
throttleEnabled: true,
throttleOption: 'project'
],
]
properties(projectProperties)
def build_sanity (SETUP_DESCRIPTION) {
IMAGE = "linux/upstream_devel-x86_64"
CLOUD_IP = "dev-l-vrt-storage"
TAGS = "test_new_setup"
if ("$SETUP_DESCRIPTION" != "b2b x86-64 cib cloud_test") {
DATA_BASE = "b2b_eth_drivertest_mini_reg_db.json"
LINK_LAYER = "eth"
}
else {
DATA_BASE = "b2b_ib_drivertest_mini_reg_db.json"
LINK_LAYER = "ib"
}
build job: 'SANITY_TESTS/new_cloud_setup_GENERAL_SANITY_CHECK2', propagate: false
parameters:
[string(name: 'SETUP_DESCRIPTION', value: "${SETUP_DESCRIPTION}"),
string(name: 'DATA_BASE', value: "${DATA_BASE}"),
string(name: 'LINK_LAYER', value: "${LINK_LAYER}"),
string(name: 'IMAGE', value: "${IMAGE}"),
string(name: 'CLOUD_IP', value: "${CLOUD_IP}"),
string(name: 'TAGS', value: "${TAGS}")]
}
try {
ansiColor('xterm') {
timestamps {
node('cloud-slave1'){
stage('Test Setups') {
if (params.RUN_STAGE == 'os_install' || params.RUN_STAGE == 'provision' || params.RUN_STAGE == 'add_jks_slave' || params.RUN_STAGE == 'add_to_noga' || params.RUN_STAGE == 'tests') {
def stepsForParrallel = [:]
def NOGA_DESCRIPTION_LIST = sh (
script: "curl -X GET 'https://noga.mellanox.com/app/server/php/rest_api/?api_cmd=get_resources&pattern=${params.SERVER_NAME}&resource_type=Setup&group_name=Yaron&sub_group=Cloud'",
returnStdout: true
).trim()
#NonCPS
def JSON = new groovy.json.JsonSlurperClassic().parseText(NOGA_DESCRIPTION_LIST)
def DESCRIPTION_LIST = JSON.data.each{
SETUP_NAME = "${it.NAME}"
SETUP_DESCRIPTION = "${it.DESCRIPTION}"
println "${it.DESCRIPTION}" // PRINT ALL DECRIPTIONS INSIDE DATA
stepsForParrallel["${it.NAME}"] = {
build_sanity(SETUP_DESCRIPTION)
}
}
parallel stepsForParrallel
}
}
}
}
}
}catch (exc) {
def recipient = "${SW_MAIL}"
def subject = "${env.JOB_NAME} (${env.BUILD_NUMBER}) Failed"
def body = """
It appears that build ${env.BUILD_NUMBER} is failing, please check HW or network stability:
${env.BUILD_URL}
"""
mail subject: subject,
to: recipient,
replyTo: recipient,
from: 'cloud-host-provision#mellanox.com',
body: body
throw exc
1) When I run it like code above build_sanity function called once and execute (instead of 3 times as expected).
2) When I take build_sanity function content and run it inside the ech loop in the tests stage it runs 3 times as expected but not choosing different parameters as expected.

so i managed to figure it out.
1) i have println some parameters and saw my function did not received the variables ok
so i have changed the build job: part and that fixed that issue.
2) i also had issue in the stage part. i put the "run parallel" inside the each loop which cause it to ran several times. so i drop it one } down and that fixed the loop issue
here is the function code + stage if anyone encounter such issue in the future
def build_sanity (SETUP_DESCRIPTION) {
if ("$SETUP_DESCRIPTION" != "b2b x86-64 cib cloud_test") {
DATA_BASE = "b2b_eth_drivertest_mini_reg_db.json"
LINK_LAYER = "eth"
}
else {
DATA_BASE = "b2b_ib_drivertest_mini_reg_db.json"
LINK_LAYER = "ib"
}
IMAGE = "linux/upstream_devel-x86_64"
CLOUD_IP = "dev-l-vrt-storage"
TAGS = "test_new_setup"
build job: 'SANITY_TESTS/new_cloud_setup_GENERAL_SANITY_CHECK',
parameters: [
string(name: 'SETUP_DESCRIPTION', value: "${SETUP_DESCRIPTION}"),
string(name: 'DATA_BASE', value: "${DATA_BASE}"),
string(name: 'LINK_LAYER', value: "${LINK_LAYER}"),
string(name: 'IMAGE', value: "${IMAGE}"),
string(name: 'TAGS', value: "${TAGS}"),
]
}
stage('Test Setups') {
if (params.RUN_STAGE == 'os_install' || params.RUN_STAGE == 'provision' || params.RUN_STAGE == 'add_jks_slave' || params.RUN_STAGE == 'add_to_noga' || params.RUN_STAGE == 'tests') {
def stepsForParrallel = [:]
def NOGA_DESCRIPTION_LIST = sh (
script: "curl -X GET 'https://noga.mellanox.com/app/server/php/rest_api/?api_cmd=get_resources&pattern=${params.SERVER_NAME}&resource_type=Setup&group_name=Yaron&sub_group=Cloud'",
returnStdout: true
).trim()
#NonCPS
def JSON = new groovy.json.JsonSlurperClassic().parseText(NOGA_DESCRIPTION_LIST)
def DESCRIPTION_LIST = JSON.data.each{
def SETUP_NAME = "${it.NAME}"
stepsForParrallel["${it.NAME}"] = {
build_sanity("${it.DESCRIPTION}")
}
}
parallel stepsForParrallel
}
}

Related

Loop through multi selection value of Jekins Parameter BooleanParam

I have on-premise Jenkins node slave that are running. The value of each param is the nodename. For example the nodename I have is (value1,value2,value3)
Suppose a user select a value1 and value2 in the parameter options in the checkbox, I want to be able to loop the selected params and pass the value to the node($selected).
That means Jenkins will connect to value1 and value2 node. Any Idea how to do this?
The code is here:
#!/usr/bin/env groovy
properties([
parameters([
booleanParam(name: 'value1', defaultValue: false, description: '') ,
booleanParam(name: 'value2', defaultValue: false, description: '') ,
booleanParam(name: 'value3', defaultValue: false, description: '')
])
])
stage('stash'){
Loop here //
node('$selected'){
}
}
Do you want to do something like the below?
node {
properties([
parameters([
booleanParam(name: 'value1', defaultValue: false, description: '') ,
booleanParam(name: 'value2', defaultValue: false, description: '') ,
booleanParam(name: 'value3', defaultValue: false, description: '')
])
])
stage('Stash') {
def list = []
if("$value1" == "true") {
list.add("value1")
}
if("$value2" == "true") {
list.add("value2")
}
if("$value3" == "true") {
list.add("value3")
}
list.each { node ->
echo "$node"
node('$node'){}
}
}
}

Jenkins pipeline, groovy map array as choises

How can I pass the array variable into the global variable in groovy?
It works perfectly without if-else.
choiceArray = []
if (appName == 'ms'){
['78', '99', '10'].each {
"${choiceArray}" << it
}
}
else if (appName == 'ms2'){
['12', '34', '56'].each {
"${choiceArray}" << it
}
}
pipeline {
parameters {
string (name: 'Branch', defaultValue: 'master', description: 'Select Branch')
choice(name: 'Environment', choices: choiceArray, description: 'Choose Environment')
if(...){
choiceArray.addAll(['78', '99', '10'])
}

Jenkins pipeline input script with one prompt only

Don't need 2 prompt in Jenkins pipeline with input script. In snippet, there is highlighted 1 and 2 where pipeline prompt 2 times for user input.
If execute this pipeline, prompt 1 will provide user to "Input requested" only, so no option to "Abort". Prompt 2 is okay as it ask to input the value and also "Abort" option.
Prompt 1 is almost useless, can we skip promt this and directly reach to prompt 2?
pipeline {
agent any
parameters {
string(defaultValue: '', description: 'Enter the Numerator', name: 'Num')
string(defaultValue: '', description: 'Enter the Denominator', name: 'Den')
}
stages {
stage("foo") {
steps {
script {
if ( "$Den".toInteger() == 0) {
echo "Denominator can't be '0', please re-enter it."
env.Den = input message: 'User input required', ok: 'Re-enter', // 1-> It will ask whether to input or not
parameters: [string(defaultValue: "", description: 'Enter the Denominator', name: 'Den')] // 2-> It will ask to input the value
}
}
sh'''#!/bin/bash +x
echo "Numerator: $Num\nDenominator: $Den"
echo "Output: $((Num/Den))"
'''
}
}
}
}
Yes, you can simplify the input by using $class: 'TextParameterDefinition'.
e.g.
pipeline {
agent any
parameters {
string(defaultValue: '', description: 'Enter the Numerator', name: 'Num')
string(defaultValue: '', description: 'Enter the Denominator', name: 'Den')
}
stages {
stage("foo") {
steps {
script {
if ( "$Den".toInteger() == 0) {
env.Den = input(
id: 'userInput', message: 'Wrong denominator, give it another try?', parameters: [
[$class: 'TextParameterDefinition', defaultValue: '', description: 'Den', name: 'den']
]
)
}
}
sh'''#!/bin/bash +x
echo "Numerator: $Num\nDenominator: $Den"
echo "Output: $((Num/Den))"
'''
}
}
}
}
If you want to go the extra mile and ask for both values:
def userInput = input(
id: 'userInput', message: 'Let\'s re-enter everything?', parameters: [
[$class: 'TextParameterDefinition', defaultValue: '', description: 'Denominator', name: 'den'],
[$class: 'TextParameterDefinition', defaultValue: '', description: 'Numerator', name: 'num']
]
)
print userInput
env.Den = userInput.den
env.Num = userInput.num

Pipeline DSL: Change build name on the fly

i would like to run some builds in parallel based on one core job (downstream job) , in the following code there is no option to change the build name on the fly, for example instead of numbers (default) , i want to get ABCDE_${number} , is that possible?
i tried to use some plugin of Version Number plug in, but i cannot set build number ....
stage ("Run Tests") {
steps {
dir("UIAutomationV2.0") {
script {
tasks = [:]
products_set = [].toSet()
features_list.each {
def featureName = it.key
tasks[featureName] = {
withEnv(["FEATURE_NAME=${featureName}"]) {
def valArr = it.value.split(",")
def productName = valArr[0]
def productPath = valArr[1]
def runnerFeaturePath = productPath.replace("UIAutomationV2.0/", '')
metaData["tests"][it.key]['phases']['Run Tests']["startTime"] = getEpochTime();
println "Run test startTime : " + metaData["tests"][it.key]['phases']['Run Tests']["startTime"]
println "Calling build for feature '${featureName}' in job '${productName}' under path ='${productPath}' "
pJob = build job: "v2_Core_Task_Runner_Slack", propagate: false, parameters: [
[$class: 'StringParameterValue', name: 'FeatureName', value: "${featureName}"],
[$class: 'StringParameterValue', name: 'FeaturePath', value: "${runnerFeaturePath}"],
[$class: 'StringParameterValue', name: 'TagName', value: "${params.TagName}"],
[$class: 'StringParameterValue', name: 'Environment', value: "${params.Environment}"],
[$class: 'BooleanParameterValue', name: 'CreateTenant', value: params.CreateTenant],
[$class: 'StringParameterValue', name: 'TagNameCondition', value: "${params.TagNameCondition}"],
[$class: 'StringParameterValue', name: 'TenantTemplate', value: "${params.TenantTemplate}"],
[$class: 'StringParameterValue', name: 'ClientLabel', value: "AGENTS_LABEL_${JOB_NAME}_${BUILD_NUMBER}"]
]
metaData["tests"][it.key]['phases']['Run Tests']["endTime"] = getEpochTime();
metaData["tests"][it.key]['consoleUrl'] = pJob.getAbsoluteUrl();
metaData["tests"][it.key]['result'] = pJob.getResult();
//pJob.nextBuildNumber = pJob.nextBuildNumber() + 1
println "Job result = " + pJob.getResult() + ", Url: " + pJob.getAbsoluteUrl()
// def nextBldNo = VersionNumber(versionNumberString: '${BUILD_DATE_FORMATTED, "yyyyMMdd"}-feature-${featureName}-${BUILDS_TODAY}')
// nextBldNo = '${nextBldNo}' + pJob.nextBuildNumber
// println "next build :: " + '${nextBldNo}'
// println "next build num >> " + VersionNumber(versionNumberString: '${BUILD_DATE_FORMATTED, "yyyyMMdd"}-feature-${featureName}-${BUILDS_TODAY}')
println "Copy artificats to 'allreports/${productName}/${featureName}'"
copyArtifacts(
projectName: 'v2_Core_Task_Runner_Slack',
filter: '**/report.json',
fingerprintArtifacts: true,
target: "allreports/${productName}/${featureName}",
flatten: true,
selector: specific(pJob.getId()),
optional: true
)
println "Run test endtime : " + metaData["tests"][it.key]['phases']['Run Tests']["endTime"]
parallel tasks
metaData["endTime"] = getEpochTime()
metDataStr = new JsonBuilder(metaData).toPrettyString()
//killPhaseCondition("NEVER")
}
}
}
}
def test = [:]
pipeline {
stages {
stage ('create map') {
steps {
script {
for (int i = 0; i < (yourCounter as Integer); i++) {
def name = i
test.put(name, testFunc(name))
}
}
}
}
stage ('run parallel') {
steps {
script {
parallel test
}
}
}
}
}
def testFunc(name) {
return {
stage ("${name}") {
node ("${name}") {
script {
echo name
}
}
}
}
}
in this way you can pass any value to testFunc() and control its params

Version Number Plugin in Jenkins declarative pipeline

I'm trying to use version number plugin to format a version number for our
packages.
From some reason the placement for the version variable doesn't work
and when I echo the following I only get the build number, for instance: "...54"
def Version_Major = '1'
def Version_Minor = '0'
def Version_Patch = '0'
pipeline {
environment {
VERSION = VersionNumber([
versionNumberString: '${Version_Major}.${Version_Minor}.${Version_Patch}.${BUILD_NUMBER}',
worstResultForIncrement: 'SUCCESS'
]);
}
stage ('Restore packages'){
steps {
script{
echo "${VERSION}"
}
}
}
}
Edit: It does look like an issue with the plugin usage since this works:
properties([
parameters([
string(name: 'Version_Major', defaultValue: '1', description: 'Version Major'),
string(name: 'Version_Minor', defaultValue: '0', description: 'Version Minor'),
string(name: 'Version_Patch', defaultValue: '0', description: 'Version Patch')
])
])
pipeline {
agent any
environment {
VERSION = "${params.Version_Major}.${params.Version_Minor}.${params.Version_Patch}.${BUILD_NUMBER}"
}
stages{
stage ('Test'){
steps {
echo "${VERSION}"
}
}
}
}
You must define the variables inside the pipeline.
Try this:
pipeline {
environment {
Version_Major = '1'
Version_Minor = '0'
Version_Patch = '0'
VERSION = VersionNumber([
versionNumberString: '${Version_Major}.${Version_Minor}.${Version_Patch}.${BUILD_NUMBER}',
worstResultForIncrement: 'SUCCESS'
]);
}
stage ('Restore packages'){
steps {
script{
echo "${VERSION}"
}
}
}
}
If you need to use a parameter instead that's also possible via:
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
usage:
"Hello ${params.PERSON}"

Resources