Reputation: 38
I have 3 nodes: A, B, C
On each of these nodes I set up a Jenkins agent with its own root directory They all have the following label: test && database && mysql
I want to run a job in parallel on all 3 nodes, to clean the workspace folder on them To achieve that, I wrote this Jenkins script
def labels = "test && mysql && database"
def getNodesName(labels){
def targets = []
def nodes = Jenkins.instance.getLabel(labels).getNodes()
for(node in nodes){
targets.add(node.getNodeName())
}
return targets
}
def nodes = getNodesName(labels)
def cleanWSTasks(targets){
tasks = [:]
for(target in targets){
tasks[target] = {
node(target){
script {
cleanWs()
}
}
}
}
return tasks
}
pipeline{
agent none
stages{
stage ('Clean Workspace'){
steps{
script{
parallel cleanWSTasks(nodes)
}
}
}
}
}
So I thought with node(target) in the cleanWsTasks function I already told Jenkins to restrict the execution of the task only on the particular target node I want. So that all 3 nodes will start cleaning their own workspaces at the same time.
However, what I see is that only 1 node picked up the task to cleanUp the workspace, and it does it 3 times.
For example, it shows:
Running on node A in ...
clean up workspace ..
Running on node A in ...
clean up workspace ..
Running on node A in ...
clean up workspace ..
What did I do wrong in my code? Please help.
Upvotes: 1
Views: 497
Reputation: 1283
The node step is working correctly, the problem you're coming across has to do with how you're defining your tasks. In your for loop, you're assigning this closure:
{
node(target){
script {
cleanWs()
}
}
to tasks[target]
.
The code inside the closure won't get evaluated until you execute the closure. So even though you assign node(target)
inside the for loop, target
's value won't get evaluated until parallel tasks
runs, which is when the closure is executed. That happens after the for loop has finished running and so target
's value is the name of the last node in your list of nodes.
An easy fix for this is to create a variable in your for loop that's equal to target and use that inside the closure, because you will force the evaluation of target
to happen inside your for loop, instead of when the closure runs.
That would look like this:
def cleanWSTasks(targets){
tasks = [:]
for(target in targets){
def thisTarget = target
tasks[thisTarget] = {
node(thisTarget){
script {
cleanWs()
}
}
}
}
return tasks
}
Upvotes: 1