I'm trying to use "JOB_BASE_NAME" jenkins environmental variable in a parameter's path in a pipeline script that gets set will building the project.
example: string(defaultValue: "/abc/test/workspace/test_${JOB_BASE_NAME}/sample", description: 'test', name: 'HOME')
but while executing the ${JOB_BASE_NAME} is not getting replaced by the value(jenkins job name). I'm unsure if I'm setting the jenkins environmental variable in the path of the parameter correctly.
thank you!
I have replicated your use case and it works for me. This is the section of code
node {
stage ('test') {
sh "echo ${HOME}"
}
}
and this is the output - (my Job name was stackoverflow)
[Pipeline] { (hide)
[Pipeline] stage
[Pipeline] { (test)
[Pipeline] sh
+ echo /abc/test/workspace/test_stackoverflow/sample
/abc/test/workspace/test_stackoverflow/sample
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Check the picture of how I set the String parameter.
I'm trying to set up a Jenkins pipeline (using the declarative syntax) that runs unit and feature tests on two separate, on-demand AWS EC2 instances. The pipeline works perfectly when run on a single instance and without the parallel stages. As soon as I switch to parallel stages, any shell script fails with this cryptic message:
process apparently never started in
/home/admin/workspace/GSWebRuby_Test#tmp/durable-b0d8c4b4 (running
Jenkins temporarily with
-Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true
might make the problem clearer)
I've googled extensively and came across several bug reports of the Durable Task plugin that appears to be responsible for this message. I'm using the latest version of the plugin v. 1.33 and none of the problems seem to apply to my case, e.g. failures on unusual architectures or when running Docker containers. I've also down- and re-upgaded the plugin (toggling between versions 1.30 and 1.33). Also, to re-iterate, sh commands work without issue when I don't use the parallel stages.
I've created a simplified pipeline to debug the problem. Note that the shell commands are also simple, e.g. "env | sort", or "pwd".
pipeline {
agent none
environment {
DB_USER = credentials('db-user')
DB_PASS = credentials('db-pass')
}
stages {
stage('Setup'){
failFast false
parallel {
stage('foo') {
agent {
label 'jenkins-slave-ondemand'
}
steps {
echo 'In stage foo'
sh 'env|sort'
}
}
stage('bar') {
agent {
label 'jenkins-slave-ondemand'
}
steps {
echo 'In stage bar'
sh 'pwd'
}
}
}
}
}
}
This is the console output:
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] withCredentials
Masking supported pattern matches of $DB_PASS or $DB_USER
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Setup)
[Pipeline] parallel
[Pipeline] { (Branch: foo)
[Pipeline] { (Branch: bar)
[Pipeline] stage
[Pipeline] { (foo)
[Pipeline] stage
[Pipeline] { (bar)
[Pipeline] node
[Pipeline] node
Still waiting to schedule task
All nodes of label ‘jenkins-slave-ondemand’ are offline
Still waiting to schedule task
All nodes of label ‘jenkins-slave-ondemand’ are offline
Running on EC2 (Jenkins AWS EC2) - Jenkins slave (i-0982299c572100c71) in /home/admin/workspace/GSWebRuby_Test
[Pipeline] {
[Pipeline] echo
In stage foo
[Pipeline] sh
Running on EC2 (Jenkins AWS EC2) - Jenkins slave (i-092ecac8e6c257270) in /home/admin/workspace/GSWebRuby_Test
[Pipeline] {
[Pipeline] echo
In stage bar
[Pipeline] sh
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-b0d8c4b4
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
Failed in branch foo
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-b6cfcff9
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
Failed in branch bar
[Pipeline] // parallel
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] End of Pipeline
ERROR: script returned exit code -2
Finished: FAILURE
Am I doing something wrong in the way I've set up the pipeline? Any pointers would be greatly appreciated.
Edit:
After setting this JENKINS_JAVA_OPTIONS org.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true, I see this additional output:
In stage bar
[Pipeline] sh
nohup: failed to run command 'sh': No such file or directory
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-099a2e56
I'm not a Jenkins guru so please be patient. :-)
I have a pipeline, something nearly as simple as this:
def hash = ''
node {
stage('Checkout') {
…
}
stage('Build') {
…
}
stage('Tests') {
…
}
}
stage('Ask deploy') {
input 'Deploy?'
}
node {
stage('Deploy') {
}
}
I want to set the value of the hash variable in the first node and read it in the next if the manual input is positive. Is this possible and safe? Is this the correct approach?
Note that there are multiple executors and manual input involved. In the Jenkins docs it is hinted for a node that:
As soon as an executor is free on a node, the steps will run.
This means that the two nodes may run in different executors, correct? Do they still share the same global variables? Thanks in advance for any clarifications!
If you have multiple slaves in Jenkins, the pipeline will be launch in one of this slaves. Every slave is different.
Every stage in you pipeline will be launch in the same slave so if you have the variable "hash" at the first line of your pipeline you wouldn't have problem to read it in all your pipeline but if you have to access to this variable value from a different build you can not access.
If you need a global variable to read it in different builds you can define a global variable using the Global Variables String Parameter Plugin
The hash variable is global and its value is available in the different executors which seems logical to me. So it looks like what I do is OK and it will work this way unless I miss something.
Here is how I've verified that (details skipped for brevity):
I've created a similar pipeline and killed the executor which ran the first node:
def gitHash;
node {
withCredentials(...) {
//Step 1:
//Check out from the SCM
stage('Prepare') {
echo "Checking out the project from source control.."
scmInfo = checkout scm
gitHash = scmInfo.GIT_COMMIT
echo "Project checked out, the GIT hash of the last commit is: ${gitHash}"
}
}
}
stage('Ask deploy') {
input 'Deploy?'
}
node {
withCredentials(...) {
stage('Deploy') {
echo "TODO, hash ${gitHash}"
}
}
}
The output from Jenkins is the following (details skipped):
Obtained Jenkinsfile from 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
Running on jnlp-13775fa128a47 in /root/workspace/...
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Prepare)
[Pipeline] echo
Project checked out, the GIT hash of the last commit is: 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] stage
[Pipeline] { (Ask deploy)
[Pipeline] input
Deploy?
Proceed or Abort
Approved by admin
[Pipeline] }
[Pipeline] // stage
[Pipeline] node
Running on jnlp-1383bdf520c9d in /root/workspace/...
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
TODO, hash 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
[Pipeline] End of Pipeline
Finished: SUCCESS
As seen the first node runs on executor jnlp-13775fa128a47 the second is on jnlp-1383bdf520c9d but the value of the globally scoped variable can be read there.
My code dynamically creates a .groovy file which triggers parameterized build inside a parallel step:
def executeParallelBuilds(){
try {
parallel(
build1BUILD: {
def build1BUILD = build job: 'TA/test1', parameters: [string(name: "CPNUM_PARAM", value: 1.141)]
},
build2BUILD: {
def build2BUILD = build job: 'TA/test2', parameters: [string(name: "CPNUM_PARAM", value: 1.141)]
},
failFast: false
)
} catch (e) {
echo "An error ocurred while building"
currentBuild.result="UNSTABLE"
}
}
return this;
Now, I load and execute the groovy file with:
node('master'){
def executeGroovyFile = load buildFilePath
executeGroovyFile.executeParallelBuilds()
}
But it seems that my pipeline cant find the Buildjobs by path.
[Pipeline] }
[Pipeline] // node
[Pipeline] node
Running on master in C:\DevApps\Jenkins\workspace\TA\pipeline_1.0_TEMPLATE
[Pipeline] {
[Pipeline] load
[Pipeline] { (D:\BuildResults_tmp\TA\MBE3\\buildString.groovy)
[Pipeline] }
[Pipeline] // load
[Pipeline] parallel
[Pipeline] [build1BUILD] { (Branch: build1BUILD)
[Pipeline] [build2BUILD] { (Branch: build2BUILD)
[Pipeline] [build1BUILD] build
[Pipeline] [build1BUILD] }
[build1BUILD] Failed in branch build1BUILD
[Pipeline] [build2BUILD] build
[Pipeline] [build2BUILD] }
[build2BUILD] Failed in branch build2BUILD
[Pipeline] // parallel
[Pipeline] echo
An error ocurred while building
[Pipeline] }
What am I doing wrong? I load and execute the .groovy file on my master so that the pipeline should be able to find the other jobs. (Without node declaration I am not able to load and execute)
EDIT: What confuses me is, that I don't get the following error:
No parameterized job named some-downtream-job-name found
There was a problem with the build call.
I saved the whole code as String to a .groovy file. This gave me some struggling with the right notation. (quotes and double qoutes)
After calling my script as:
def build1BUILD = build job: BuildJobNameList[i], parameters: [string(name: "CPNUM_PARAM", value: 1.141)]
everything works fine
I'm currently using the Build Flow plugin, which seems to have been abandoned in favor of Pipelines in Jenkins 2.0.
Running into some problems re-building our existing jobs using the new pipelines.
Currently, I have code similar to this:
ignore(FAILURE) {
join = parallel([
job1: {build('job1')},
job2: {build('job2')},
job3: {build('job3')}
])
}
results = [join.job1.result.toString(), join.job2.result.toString(), join.job2.result.toString()]
if(join.job1.result.toString() == 'SUCCESS') {
buildList << join.job1.lastBuild.getDisplayName()
}
The goal here is to run multiple existing jobs in parallel, and then access information about the builds that completed. This has been working without issue in the Build Flow plugin.
I have been unable find a way to access this data using the new Pipelines.
echo 'Checking streams for latest builds'
join = [:]
join['Job1'] = { build job: 'Job1', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false}
join['Job2'] = { build job: 'Job2', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false}
join['Job3'] = { build job: 'Job3', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false}
parallel join
A dump of join['Job1'] doesn't give access to an AbstractBuild or similar, the way the Build Flow plugin does. Instead, it shows:
<org.jenkinsci.plugins.workflow.cps.CpsClosure2#2eac6ed9
def=com.cloudbees.groovy.cps.impl.CpsClosureDef#59647704
delegate=WorkflowScript#3aa1807f
owner=WorkflowScript#3aa1807f
thisObject=WorkflowScript#3aa1807f
resolveStrategy=0
directive=0
parameterTypes=null
maximumNumberOfParameters=0
bcw=null>
Using the new Pipelines, is there a way to access data like job1.result, job1.lastBuild, job1.lastBuild.getDisplayName()?
a little late but you can also define the runWrapper object returned by build command in your closure and place it in a map defined outside of the parallel command.
Here's an example. Note: I am using propagate: false so that exceptions (JUnit test failures, etc) are not thrown. You would have to decide how you want to handle exceptions, try/catch/finally, etc.
Example Pipeline Job to execute (needs to be parameterized with a string param commandStr):
env.PASSED_CMD="${params.commandStr}"
stage('command-exec') {
node {
sh "${commandStr}"
}
}
Executing job (config):
buildRuns = [:]
buildResults = [:]
def buildClosure(String jobKey, String paramAValue) {
return {
def runWrapper = build(
job: 'command-test-job',
propagate: false,
parameters: [[$class: 'StringParameterValue', name: 'commandStr', value: paramAValue]]
)
buildResults."$jobKey" = runWrapper
}
}
buildRuns."job1" = buildClosure("job1", "echo 'HI' && exit 0")
buildRuns."job2" = buildClosure("job2", "echo 'HO' && exit 0")
parallel buildRuns
for(k in buildRuns.keySet()) {
def runResult = buildResults."$k"
echo "$k -> ${runResult.result}"
echo "$k -> ${runResult.buildVariables.PASSED_CMD}"
}
The build log shows:
[Pipeline] parallel
[Pipeline] [job1] { (Branch: job1)
[Pipeline] [job2] { (Branch: job2)
[Pipeline] [job1] build (Building command-test-job)
[job1] Scheduling project: command-test-job
[Pipeline] [job2] build (Building command-test-job)
[job2] Scheduling project: command-test-job
[job1] Starting building: command-test-job #7
[job2] Starting building: command-test-job #8
[Pipeline] [job2] }
[Pipeline] [job1] }
[Pipeline] // parallel
[Pipeline] echo
job1 -> SUCCESS
[Pipeline] echo
job1 -> echo 'HI' && exit 0
[Pipeline] echo
job2 -> SUCCESS
[Pipeline] echo
job2 -> echo 'HO' && exit 0
[Pipeline] End of Pipeline
Finished: SUCCESS
This is very similar to Steve-B's Answer, but you don't actually need to define the runwrapper explicitly or place it in the additional map before hand.
tl;dr You can just store the parallel build to a hashMap and access that map by directly looping over it's keySet instead
Take this answer with a grain of salt, I am using an older version of pipeline (Jenkins 2.7.2 and Pipeline 2.2).
You can store the parallel build results to a hashMap and loop over the map's keySet to get some information about the build.
def create_build_job(job_name, pool_label="master", propagate=false) {
build job: job_name, parameters: [[$class: 'LabelParameterValue', name: "node_label", label: "${pool_label}"]], propagate: propagate, wait:true
}
def buildmap = [:]
def build_results
stage 'Perform Build'
//test1 is set to fail, test2 is set to succeed
buildmap['test1'] = {create_build_job('test1', "your_node_label")}
buildmap['test2'] = {create_build_job('test2', "your_node_label")}
build_results = parallel buildmap
for(k in build_results.keySet()){
println build_results["${k}"].getProperties()
}
For this pipeline I'm just dumping all of the properties of the RunWrapper stored in item in the map, however you can access each property directly, so if you want the result of the build you can just do:
build_results["${k}"].result
The console output produced by this pipeline (with any potentially identifying information redacted is:
Started by user <user>
[Pipeline] stage (Perform Build)
Entering stage Perform Build
Proceeding
[Pipeline] parallel
[Pipeline] [test1] { (Branch: test1)
[Pipeline] [test2] { (Branch: test2)
[Pipeline] [test1] build (Building test1)
[test1] Scheduling project: test1
[test1] Starting building: test1 #11
[Pipeline] [test2] build (Building test2)
[test2] Scheduling project: test2
[test2] Starting building: test2 #11
[Pipeline] }
[Pipeline] }
[Pipeline] // parallel
[Pipeline] echo
{rawBuild=test1 #11, class=class org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper, absoluteUrl=<jenkins_url>/job/test1/11/, buildVariables={}, previousBuild=org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper#1480013a, id=11, nextBuild=null, changeSets=[], result=FAILURE, description=null, startTimeInMillis=1509667550519, timeInMillis=1509667550510, duration=956, number=11, displayName=#11}
[Pipeline] echo
{rawBuild=test2 #11, class=class org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper, absoluteUrl=<jenkins_url>/job/test2/11/, buildVariables={}, previousBuild=org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper#2d9c7128, id=11, nextBuild=null, changeSets=[], result=SUCCESS, description=null, startTimeInMillis=1509667550546, timeInMillis=1509667550539, duration=992, number=11, displayName=#11}
[Pipeline] End of Pipeline
Finished: SUCCESS
You can access that data by using the Jenkins API after the parallel step:
Jenkins.instance.getItemByFullName('Job1').lastBuild