Using jenkins pipeline agent label based on parameter value choice - jenkins

I have this example pipeline(part of it):
pipeline {
parameters {
choice(name: 'myParam', choices: ['1','2'], description: 'param desc')
}
options { timestamps () }
agent {
node {
label 'myLabel'
}
}
my question is this:
I would like to change myLabel for my agent label based on users choice of myParam.
in this case i want that when myParam is 1 then myLabel would be equal to "linux_first" and when myParam is 2 then myLabel would be "linux_second".
Does anyone know a way to do it?
Thanks in advance,
Alon

You can parameterize the agent this way in the declarative pipeline
properties([
string(description: 'build Agent', name: 'build_agent')
])
pipeline {
agent {
label params['build_agent']
}
stages {
// steps
}
}

Approach 1-
You can try "nodeLabelParameter" plugin. It might help you based on your requirement.
https://plugins.jenkins.io/nodelabelparameter/
This plugin adds two new parameter types to job configuration - node and label. The new parameters allow dynamic selection of the node or label where a job should be executed.
Approach 2-
Also Basic syntax would be to define parameter for pipeline and consume it.
agent {
label "${build_agent}"
}

Related

Accessing choice parameter values from within Jenkins declarative pipelines

In my declarative pipeline I have a choice parameter as follows:
parameters {
choice(name: 'sleep_time',
choices: ['2.5m', '2m', '15s', '50s', '4m', '1m', '1.5m', '1.5s', 'random'],
description: "the sleep time to execute after the command")
}
How can I get all the values of the parameter from within my declarative pipeline?
In this example I am expecting to get the list of 2.5m, 2m, 15s and so on.
During execution the parameter value will hold only the selected choice and not the entire list of options, however because the parameter is defined as part of the pipeline script, you can define the option list as a global parameter for your pipeline and use in in the parameter definition and in any other place in the pipeline.
Something like:
// Define the options as a global parameter
SLEEP_OPTIONS = ['2.5m', '2m', '15s', '50s', '4m', '1m', '1.5m', '1.5s', 'random']
pipeline {
agent any
parameters {
choice(name: 'sleep_time',
choices: SLEEP_OPTIONS, // Use the global parameter
description: "the sleep time to execute after the command")
}
stages {
stage('Use Global Parameter') {
steps {
script {
SLEEP_OPTIONS.each { // SLEEP_OPTIONS is available for all steps in the pipeline
println it
}
}
}
}
}
}

run 2 jobs with same jenkinsfile and different parameters

I want to configure 2 jobs in Jenkins that use the same jenkinsfile but the only difference is the parameters to these jobs.
for example:
create 2 jobs named: A and B that each one of them gets param of X.
in A the job get X as 1 and in B the X is 2.
I want to create it in this way instead of one job that has multi-checkbox because the jobs are independent and I don't want to leave any option to make mistakes.
How can I achieve that only via jenkinsfile?
I read about load jenkinsfile within other jenkinsfile but can't find a way to pass parameters.
How can I achieve this?
If you use Build with Parameters you can reference these declared parameters in the Jenkinsfile with this syntax ${PARAM}.
You could also declare a Choice Parameter named CHOICE in a declaritive pipeline it would look like this:
pipeline {
agent any
parameters {
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
}
stages {
stage('Example') {
steps {
echo "Choice: ${params.CHOICE}"
}
}
}
}
You would not need 2 jobs this way. It is the same job but it runs with different configurations for CHOICE.
This example is directly taken from the official docs:
https://www.jenkins.io/doc/book/pipeline/syntax/#parameters
my solution was:
in Jenkins file to set
environment {
X= getX(env.JOB_NAME)
Y= getY(env.JOB_NAME)
}
and create the following functions in the end of pipeline:
def getX(jobName)
{
if (jobName.contains("X1"))
{
return "X1";
}
else return "X2";
}
def getY(jobName)
{
if (jobName.contains("BLA"))
{
return "BLA1";
}
return "BLA2";
}

Dynamic parameter value depending on Jenkins agent label

I got choice parameter defined in pipeline consisting of couple of items. I got 2 types of jenkins agents, each of the with custom label set on. Is it possible to set ordering of choice items depending on which agent is running pipeline. I'm thinking of sth like this:
def VALUES
pipeline {
agent {
label 'agentone || agenttwo'}
}
//not an actual code
if agent_name == agentone
VALUES=['item1', 'item2']
if agent_name == agentwo
VALUES=['item2', 'item1']
////////
.....
parameters {
choice(name: 'ITEMS', choices: "${VALUES}.join('\n')")
}
Thanks in advance for any suggestions.

How can I parameterize Jenkinsfile jobs

I have Jenkins Pipeline jobs, where the only difference between the jobs is a parameter, a single "name" value, I could even use the multibranch job name (though not what it's passing as JOB_NAME which is the BRANCH name, sadly none of the envs look suitable without parsing). It would be great if I could set this outiside of the Jenkinsfile, since then I could reuse the same jenkinsfile for all the various jobs.
Add this to your Jenkinsfile:
properties([
parameters([
string(name: 'myParam', defaultValue: '')
])
])
Then, once the build has run once, you will see the "build with parameters" button on the job UI.
There you can input the parameter value you want.
In the pipeline script you can reference it with params.myParam
Basically you need to create a jenkins shared library example name myCoolLib and have a full declarative pipeline in one file under vars, let say you call the file myFancyPipeline.groovy.
Wanted to write my examples but actually I see the docs are quite nice, so I'll copy from there. First the myFancyPipeline.groovy
def call(int buildNumber) {
if (buildNumber % 2 == 0) {
pipeline {
agent any
stages {
stage('Even Stage') {
steps {
echo "The build number is even"
}
}
}
}
} else {
pipeline {
agent any
stages {
stage('Odd Stage') {
steps {
echo "The build number is odd"
}
}
}
}
}
}
and then aJenkinsfile that uses it (now has 2 lines)
#Library('myCoolLib') _
evenOrOdd(currentBuild.getNumber())
Obviously parameter here is of type int, but it can be any number of parameters of any type.
I use this approach and have one of the groovy scripts that has 3 parameters (2 Strings and an int) and have 15-20 Jenkinsfiles that use that script via shared library and it's perfect. Motivation is of course one of the most basic rules in any programming (not a quote but goes something like): If you have "same code" at 2 different places, something is not right.
There is an option This project is parameterized in your pipeline job configuration. Write variable name and a default value if you wish. In pipeline access this variable with env.variable_name

Can I define multiple agent labels in a declarative Jenkins Pipeline?

I'm using declarative Jenkins pipelines to run some of my build pipelines and was wondering if it is possible to define multiple agent labels.
I have a number of build agents hooked up to my Jenkins and would like for this specific pipeline to be able to be built by various agents that have different labels (but not by ALL agents).
To be more concrete, let's say I have 2 agents with a label 'small', 4 with label 'medium' and 6 with label 'large'. Now I have a pipeline that is very resource-low and I want it to be executed on only a 'small'- or 'medium'-sized agent, but not on a large one as it may cause larger builds to wait in the queue for an unnecessarily long time.
All the examples I've seen so far only use one single label.
I tried something like this:
agent { label 'small, medium' }
But it failed.
I'm using version 2.5 of the Jenkins Pipeline Plugin.
You can see the 'Pipeline-syntax' help within your Jenkins installation and see the sample step "node" reference.
You can use exprA||exprB:
node('small||medium') {
// some block
}
EDIT: I misunderstood the question. This answer is only if you know
which specific agent you want to run for each stage.
If you need multiple agents you can declare agent none and then declare the agent at each stage.
https://jenkins.io/doc/book/pipeline/jenkinsfile/#using-multiple-agents
From the docs:
pipeline {
agent none
stages {
stage('Build') {
agent any
steps {
checkout scm
sh 'make'
stash includes: '**/target/*.jar', name: 'app'
}
}
stage('Test on Linux') {
agent {
label 'linux'
}
steps {
unstash 'app'
sh 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
stage('Test on Windows') {
agent {
label 'windows'
}
steps {
unstash 'app'
bat 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
}
}
This syntax appears to work for me:
agent { label 'linux && java' }
As described in Jenkins pipeline documentation and by Vadim Kotov one can use operators in label definition.
So in your case if you want to run your jobs on nodes with specific labels, the declarative way goes like this:
agent { label('small || medium') }
And here are some examples from Jenkins page using different operators
// with AND operator
agent { label('windows && jdk9 )') }
// a more complex one
agent { label('postgres && !vm && (linux || freebsd)') }
Notes
When constructing those definitions one just needs to consider following rules/restrictions:
All operators are left-associative
Labels or agent names can be surrounded with quotation marks if they contain characters that would conflict with the operator syntax
Expressions can be written without whitespace
Jenkins will ignore whitespace when evaluating expressions
Matching labels or agent names with wildcards or regular expressions is not supported
An empty expression will always evaluate to true, matching all agents
Create a another label call 'small-or-medium' that has 6 all agents. Then in Jenkinsfile:
agent { label 'small-or-medium' }

Resources