Jenkins Pipeline File - Passing Jenkinsfile variables into further commands
Issue:
In passing a variable declared within Jenkinsfile to a sh
command that ssh's and executes on a remote host, the variable contents are not retained on the remote host.
Built-in Jenkins variables retain fine both locally and on the remote host. The variable I've defined works fine locally but doesn't translate on the remote host.
Although this issue references Docker, this is actually 100% Jenkins pipeline-based as it could apply to any example with or without Docker.
Background:
I'm trying to dynamically create an image name based on the current build tag and put that name into a variable.
Then I pass that variable into the sh
step which remotes over to a Docker host and runs a build step with the name defined.
Snippet of applicable parts of Jenkinsfile...
// The below stage just echo's out some stuff into a file dockerimgname.jenkins.out
stage ('Construct Img name') {
sh '''echo ${BUILD_TAG} | awk '{print tolower($0)}' | sed 's/jenkins-//' > dockerimgname.jenkins.out'''
}
// This stage reads that file from previous stage and puts the value into variable.
// The variable is echo'd locally which works perfectly. Then ssh is called to execute command on remote host. That's where the variable value doesn't work.
stage ('Build Target Container') {
def jobBaseName = readFile 'dockerimgname.jenkins.out'
echo "${jobBaseName}"
sh 'ssh -i ~/ssh_keys/key.key user@somehost "cd /dockerdata/build/${BUILD_TAG} && docker build -t localrepo/${jobBaseName}:${BUILD_NUMBER} ."'
}
Normally I would assume it doesn't have the variables since it's a remote host... However it is odd that ${BUILD_NUMBER}
and ${BUILD_TAG}
translate and work fine on the remote host. Why doesn't ${jobBaseName}
?? (it comes out empty/null on remote host).
Since it's not guaranteed that your individual stages will run on the same executor node (unless you have the stages wrapped up in the same node
block), using files to share information between stages will be unreliable. Instead use variables:
def jobBaseName
stage ('Construct Img name') {
jobBaseName = sh(
script: "echo ${BUILD_TAG} | awk '{print tolower($0)}' | sed 's/jenkins-//'",
returnStdout: true,
)
}
stage ('Build Target Container') {
sh "ssh -i ~/ssh_keys/key.key user@somehost 'cd /dockerdata/build/${BUILD_TAG} && docker build -t localrepo/${jobBaseName}:${BUILD_NUMBER} .'"
}
By the way, I would also suggest using sshAgent
and Jenkins' built-in credentials store to manage SSH keys instead of manually passing in the -i
flag to SSH.