Label conditions for multiple slave in declarative pipeline of Jenkins - jenkins-pipeline

I am trying to use the below :
pipeline {
agent { label 'slave1 || slave2' }
stages{
}
}
When I am using the above format, the job is executing in slave1. But when I am reversing the format i.e
agent { label 'slave2 || slave1' }, its still executing on slave1.
Could you please help in clarifying is it the expected way of working. Isn't it something like the label written first, is given first precedence .

This is a feature of Jenkins, not a bug. It tries to be consistent in choosing a slave, as this has a potential of saving some time. For example, on a slave that was used previously, the results of a checkout may still be in the workspace.
Since slave1 fits both the requirements of 'slave1 || slave2' and 'slave2 || slave1', Jenkins will use it. If it's unavailable or busy, some other slave will be used instead.

Related

How to trigger multibranch downstream job with jobname/{env.BRANCH_NAME}

I've 2 multibranch jenkins pipeline jobs connecting same github project. I'm triggering first MB job ex. dev. branch, now on success of this job I want to trigger second MB job with same branch name. (I've separate Jenkinsfile fot both MB job).
I've tried below options but didn't work:
(1)
build job: 'jobName', parameters: [[$class: 'StringParameterValue', name: 'BRANCH_NAME', value: env.BRANCH_NAME]]
This gives me error "Waiting for non-job items is not supported"
(2)
build job: 'jobName/${branch_name}'
This gives me jobname/${branch_name} does not exist means variable here is not resolving, I've created this variable in environment directive
Simple jobName/dev if I'd give hardcode in Jenkinsfile then it's working, but I'd need it with automatically selecting branch name.
please advise, thanks.
When you want to use variables inside your string you need to use double quotes, example:
$"BRANCH_NAME"
From the groovy docs:
"Any Groovy expression can be interpolated in all string literals,
apart from single and triple-single-quoted strings. "
More here:
https://docs.groovy-lang.org/latest/html/documentation/#all-strings
An alternative could also be to use concatenation:
build job:'job/'+somebranchvariable, parameters:[string(name: 'BUILD_NAME', value: build_name)]
I have tried this format, it is working.
build(job: "JOBNAME" + "/" + "${BRANCH_NAME}".replaceAll('/', '%2F'))
Forward slash (/) is converted to %2f in the job name:
It’s a common practice to use a forward slash (/) when creating feature branches within developer teams, so whenever a new Pipeline gets created automatically with the creation of a new branch, / will get converted into %2f.
Whenever you are referencing the branch name in the job or calling any job as a downstream, you will have to make sure of this conversion. Look at the below example where we are trying to call a downstream project.
I've found another solution for this issue:
In the jenkinsfile triggering pipeline job with gitParameter:
build job: 'jobName', parameters: [gitParameter(name: 'GITBRANCH', value: env.BRANCH_NAME)]
Installed "git parameter" plugin, and configure in job which is being triggered in jenkinsfile
parameters {
gitParameter branchFilter: 'origin/(.*)', defaultValue: 'master', name: 'GITBRANCH', type: 'PT_BRANCH'
}
And calling this parameter while checkout code
stage("Checkout Branch wise"){
steps{
git branch: "${params.GITBRANCH}", url: 'https://xxx/xxx/xxxx.git'
}
}
which solved the problem.

Jenkins Pipeline emailext: How to access build object in pre-send script

I'm using Jenkins ver. 2.150.1 and have some freestyle jobs and some pipeline jobs.
In both job types I am using the emailext plugin, with template and pre-send scripts.
It seems that the build variable, which is available in the freestyle projects, is null in the pipeline projects.
The pre-send script is the following (just an example, my script is more complex):
msg.setSubject(msg.getSubject() + " [" + build.getUrl() + "]")
There is no problem with the msg variable.
In the freestyle job, this script adds the build url to the mail subject.
In the pipeline job, the following is given in the job console:
java.lang.NullPointerException: Cannot invoke method getUrl() on null object
The invocation of emailext in the pipeline job is:
emailext body: '${SCRIPT, template="groovy-html.custom.pipeline.sandbox.template"}',
presendScript: '${SCRIPT, template="presend.sandbox.groovy"}',
subject: '$DEFAULT_SUBJECT',
to: 'user#domain.com'
I would rather find a general solution to this problem (i.e. Access the build variable in a pipeline pre-send script), but would also appreciate any workarounds to my current needs:
Access job name, job number, and workspace folder in a pipeline pre-send script.
I have finally found the answer -
Apparently for presend script in pipeline jobs, the build object does not exist, and instead the run object does. At the time I posted this question this was still undocumented!
Found the answer in this thread
Which got the author to update the description in the wiki:
run - the build this message belongs to (may be used with FreeStyle or Pipeline jobs)
build - the build this message belongs to (only use with FreeStyle jobs)
You can access the build in a script like this:
// findUrl.groovy
def call(script) {
println script.currentBuild.rawBuild.url
// or if you just need the build url
println script.env.BUILD_URL
}
and would call the script like this from the pipeline:
stage('Get build URL') {
steps {
findUrl this
}
}
The currentBuild gives you a RunWrapper object and the rawBuild a Run. Hope this helps.

Can Jenkins pipeline use variables in agent stage?

Problem
I'm using Jenkins pipeline and testing python with tox.
This combination explodes when tox creates a python virtualenv with a pip
whose shebang line exceeds the hard coded system imposed maximum of 127 characters.
To set a shorter workspace location,I want to add:
agent {
node {
label 'debian-slave'
customWorkspace "workspace/${env.GIT_BRANCH}"
}
}
but env.GIT_BRANCH is not yet defined. environment has not yet been calculated when the agent block runs.
How can I add the branch number or something similar to the workdir definition?
I don't want to lose the per-branch unique workspaces.
What Jenkins variables exist at the "agent" stage?

Jenkins Pipeline: Enable timestamps in build log console

How can I display build timestamps for each line of a multi-branch pipeline project? Is it a supported feature? If yes, does it need to be enabled in the Jenkinsfile or is there a GUI option?
Adding options to the declarative pipeline
pipeline {
agent any
options { timestamps () }
// stages and rest of pipeline.
}
Credit goes to the comment above Jenkins Pipeline: Enable timestamps in build log console
For scripted pipeline just wrap your script in timestamps { }
Eg.
timestamps {
// do your job
}
Note: You must have the timestamper plugin installed: wiki.jenkins.io/display/JENKINS/Timestamper
I'm wondering why #roomsg comment on the accepted answer didn't become an answer.
I just noticed that (at least in our setup) you can configure this
globally: check the "Enabled for all Pipeline builds" in the
"Timestamper" section in Jenkins configuration
I think this is the best answering for Q. So,in case you have access as admin you can set it for all pipeline jobs through GUI

Jenkins: How to get node name from label to use as a parameter

I need to give a server name to a maven build. During the maven build this server name will be used to make a call that server do some tests on that server.
Our servers have jenkins slaves on them and is grouped using labels
Example
Slaves/Node | Label
Server1 | BackEndServers
Server2 | BackEndServers
Server3 | FrontEndServers
Server4 | FrontEndServers
With Elastic Axis plugin i can say run my Jenkins job on this Node Label (for example on BackEndServers) and the same project will be executed on both of the servers (Server1 & Server2).
In my case I cannot do this as maven is not installed on the BackEndServers where my code is running. But the maven build needs to know about the server names though.
So is there a way how I can get the server names from a label and then run the same job multiple times passsing each servername to the maven build?
Example
Giving that I have the label 'BackEndServers'
obtain a list of node names 'Server1,Server2'
and run my job for each node name and pass a parameter to it
aka
Having Job (with parameter Server1)
Having Job (with parameter Server2)
Use Jenkins environment variables like NODE_NAME in the Maven command of the build job as value for a system property. For example:
mvn clean install -Djenkins.node.name=${NODE_NAME}
In your Maven project (pom.xml) configure the plugin, which requires the node name, with the help of following property: ${jenkins.node.name}
Here are some links - how to trigger Jenkins builds remotely:
How to trigger Jenkins builds remotely and to pass paramter
Triggering builds remotely in Jenkins
Launching a build with parameters
I don't, if it is possible in the way you want it. But the provided information should help you to find a solution.
Try Jenkins.getInstance().getComputer(env.NODE_NAME).getNode() See more on official Doc
In the end I created a 2 jobs.
To interogate the Jenkens nodes for me and build up a string of servers to use
Then use Dynamic Axis lable with the list I have in Job 1 to execute my maven build
In Job 1 - I used The EnjEnv plugin and it has a 'Evaludated Groovy Script' section that basically you can do anything... but it should return a property map. I don't know how to return a value from a Groovy script so this worked kewl for me as I can reference property (or Environment variables) from almost anyware
import hudson.model.*
String labelIWantServersOf = TheLabelUsedOnTheElasticAxisPlugin; // This is the label assosiated with nodes for which i want the server names of
String serverList = '';
for (aSlave in hudson.model.Hudson.instance.slaves) {
out.println('Evaluating Server(' + aSlave.name + ') with label = ' + aSlave.getLabelString());
if (aSlave.getLabelString().indexOf(labelIWantServersOf ) > -1) {
serverList += aSlave.name + ' ';
out.println('Valid server found: ' + aSlave.name);
}
}
out.println('Final server list where SOAP projects will run on = ' + serverList + ' which will be used in the environment envInject map');
Map<String, String> myMap = new HashMap<>(2);
myMap.put("serverNamesToExecuteSoapProjectOn", serverList );
return myMap;
Then I had some issue to pass the Environment var onto my next job. So I simply wrote the values that I wanted to a property file using a windows batc script in the Build process
echo serverNamesToExecuteSoapProjectOn=%serverNamesToExecuteSoapProjectOn%> baseEnvMap.properties
Then as a post build action I had a "Trigger parameterized build on other projects' calling my 2nd job and I passed the baseEnvMap.properties to it.
Then on my Job 2 which is a Multiconfig job I added a Dynamic Axis using the environment var that was passed via the property file to job 2.
This will duplicate Job 2 and execute it each time with the value that the groovy script build up which I can reference in my mvn arguments.
To list out all nodes of label name LABELNAME:
http://ServerIP:8080/label/LABELNAME/api/json?pretty=true

Resources