I have a pipeline that is dynamically creating multiple parallel stages, effectively executing the same steps on a user-defined number of agents/Windows clients (set at execution). I want to have each agent/client use a different user.
The number of parallel agents running the steps is defined by the parameter, AGENT_COUNT.
In the simplified pipeline below, there is a simple 1-step command using "net use" to map a drive. In live, I have the Windows user and password hardcoded but I want to have each agent/client use a different user. I have used the WINUSER variable to define the user name, taking the counter value from the for loop as a suffix to the WINUSER string. The echo that I inserted (as debug) after is to verify the value of WINUSER at that point. On execution with AGENT_COUNT = 3, I see the value of WINUSER change from 'test1' to 'test2', 'test3' as the for loop executes, which exactly what I want. However, in the net use command and in the echo in the generated stages, all 3 agents run with the user as 'test3', i.e. the last value from the for loop.
How do I get the different user names to propagate? Thanks in advance for any help.
(apologies if the formatting is messed up)
def parallelStagesSoak = [:]
def stagesToBuild = []
pipeline {
agent none
parameters {
string(name: "AGENT_COUNT", defaultValue: "1", trim: true, description: "How many Windows agents to run the test")
string(name: "HNAS_PATH_WIN", defaultValue: "\\\\server1\\dir", trim: true, description: "path to share")
string(name: "MAP_DRIVE_WIN", defaultValue: "P", trim: true, description: "drive letter to use in Windows")
}
stages {
stage("soak_test") {
steps {
script {
def WINUSER
// defines the number of agents/clients that will connect to server
for (int i=1; i<="$params.AGENT_COUNT".toInteger();i++) {
WINUSER="test"+i.toString()
stagesToBuild.add("win_agent_"+i.toString())
echo "WINUSER="+WINUSER
}
// generates the defined number of agents/clients to run in parallel
stagesToBuild.each { s ->
parallelStagesSoak[s] = {
echo "WINUSER in test="+WINUSER
node(label: "soak-client && windows") {
stage(s) {
bat "net use $params.MAP_DRIVE_WIN: $params.PATH_WIN /user:domain1\\$WINUSER test"
}
}
}
}
parallel parallelStagesSoak
}
}
}
}
}
This is an obscure feature of Java closures (and what you collect in the map is a closure) but it can be easily curcumvented:
script {
// defines the number of agents/clients that will connect to server
for (int i=1; i<="$params.AGENT_COUNT".toInteger();i++) {
def stage_name = "win_agent_${i}"
String this_user = "test${i}"
parallelStagesSoak[stage_name] = {
echo "this_user is ${this_user}"
node(label: "soak-client && windows") {
bat "net use ... /user:domain1\\${this_user} test"
}
}
}
parallel parallelStagesSoak
}
My output (truncated for readablity):
this_user is test1
[Pipeline] node
[Pipeline] echo
this_user is test2
[Pipeline] node
[Pipeline] echo
this_user is test3
[Pipeline] node
Running on z02 in .../workspace/...
[Pipeline] {
[Pipeline] echo
bat net use /user:domain1\test1 test
[Pipeline] }
Running on z02 in .../workspace/...
Running on z01 in .../workspace/...
[Pipeline] // node
[Pipeline] }
[Pipeline] {
[Pipeline] {
[Pipeline] echo
bat net use /user:domain1\test2 test
[Pipeline] }
[Pipeline] echo
bat net use /user:domain1\test3 test
[Pipeline] }
[Pipeline] // node
[Pipeline] // node
[Pipeline] }
[Pipeline] }
[Pipeline] // parallel
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS```