Issue
I would like to do theses steps in a Jenkins pipeline:
- Build a RPM (for CentOS) on a builder node
- Create a new proxmox container from the master node (curl to call the PVE API)
- Copy the built RPM from the builder node to the container node to test the yum install
- etc.
The initial working code, from a terminal or a bash script was:
// Retrieving the CT list in the VMID range 901 --> 999
VMID_LIST=$(curl --insecure --silent --cookie "$(<~/PVE_API/cookie)" -X GET https://my-proxmox:8006/api2/json/nodes/my-node/lxc | jq '.' | grep vmid | sort | cut -d'"' -f4 | grep "9[0-9][0-9]")
// Determine the first available integer
for i in $(seq 901 999)
do
if ! echo "$VMID_LIST" | grep $i
then
CT_VMID=$i
break
fi
done
// Creating my proxmox container
curl command...
When I'm trying to execute sh/bash commands during some steps, many times it fails...
I have created and little pipeline to explain my error.
pipeline {
agent { label 'master' }
stages {
stage("Create container") {
steps {
script {
SEQ = sh(returnStdout: true, script: 'seq 1 9').trim()
sh "echo '${SEQ}'"
CTID = sh(returnStdout: true, script: "for id in '${SEQ}'; do echo $id; done").trim()
sh "echo '${CTID}'"
}
}
}
}
}
Same result if I use triple double-quote:
pipeline {
agent { label 'master' }
stages {
stage("Create container") {
steps {
script {
SEQ = sh(returnStdout: true, script: 'seq 1 9').trim()
sh "echo '${SEQ}'"
sh """
for id in '{$SEQ}'
do
echo $id
done
"""
}
}
}
}
}
Result:
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /home/jenkins/.jenkins/jobs/Services/jobs/hello_world/branches/my_branch-7.15773s/workspace
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
The recommended git tool is: git
[...snip...]
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Create container)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ seq 1 9
[Pipeline] sh
+ echo '1
2
3
4
5
6
7
8
9'
1
2
3
4
5
6
7
8
9
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: id for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:270)
at org.kohsuke.groovy.sandbox.impl.Checker$7.call(Checker.java:353)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:357)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:9)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
at sun.reflect.GeneratedMethodAccessor336.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:83)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:312)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:276)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:139)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:68)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE
How to run sh/bash scripts in Jenkins steps as expected?
What is the best practices to do all checks or linux native commands in a Jenkins pipeline?
Why Jenkins offers a way to use sh/bash commands and not so many of them work as expected?
How Jenkins experts do similar things than what I would like to do?
Solution
You will need to escape $id
to \$id
otherwise Jenkins thinks you are trying to use a Groovy var rather than a shell var.
i.e.
pipeline {
agent { label 'master' }
stages {
stage("Create container") {
steps {
script {
SEQ = sh(returnStdout: true, script: 'seq 1 9').trim()
sh "echo '${SEQ}'"
sh """
for id in '{$SEQ}'
do
echo \$id
done
"""
}
}
}
}
}
Will give you
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Create container)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ seq 1 9
[Pipeline] sh
+ echo 1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
[Pipeline] sh
+ echo {1 2 3 4 5 6 7 8 9}
{1 2 3 4 5 6 7 8 9}
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
The other issue you may have in this is that seq
adds a newline after every number it prints so your for loop wont work as that expects space separated values rather than new line so that would need fixing in for your example to work as you expect.
Answered By - apr_1985