5

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).

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
emmdee
  • 1,935
  • 9
  • 35
  • 56
  • Are you sure that your shell command writes something meaningful to the `dockerimgname.jenkins.out` file? Have you logged in to the executor node and verified this? – jayhendren Nov 23 '17 at 03:49
  • Thanks for the input. Yes, I have verified it looks right in the file. I would rather not use a file at all but am having problems with the variable declaration being global between stages so the file was a workaround. Regardless, yes I've verified the file contents look good. – emmdee Nov 24 '17 at 16:53
  • Are you sure it's not string interpolation inside single quotes? Try ```echo 'ssh -i ~/ssh_keys/key.key user@somehost "cd /dockerdata/build/${BUILD_TAG} && docker build -t localrepo/${jobBaseName}:${BUILD_NUMBER} ."'``` – MaratC Dec 11 '18 at 15:11

1 Answers1

4

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.

jayhendren
  • 917
  • 4
  • 11
  • This is exactly what I was looking for. I was having issues with the declared variable passing between stages. Since you're declaring it outside of the stages that may resolve it. I'll give this a shot. – emmdee Nov 24 '17 at 16:53
  • Jenkins is complaining about syntax with the above. `WorkflowScript: 10: unexpected token: echo` the `^` in the error log is pointing to the double quote `"` on the `script "echo` line – emmdee Nov 24 '17 at 17:38
  • Pretty sure I just missed a colon. Should be `script: "..."`. Updated. – jayhendren Nov 24 '17 at 23:55
  • @jayhendren could you give a pointer to using Credentials and SSH in the intended way? I fell back on "withCredentials", that feels like a kludge... – Samuel Åslund Oct 01 '18 at 11:50
  • 1
    @SamuelÅslund the instructions for using credentials with SSHAgent are [here in the official docs](https://jenkins.io/doc/pipeline/steps/ssh-agent/). You just need to supply the name of the credentials as an argument to `sshagent`, i.e. `sshagent(credentials: ['my-credentials-id']) { sh 'ssh myuser@myhost ...' }`. – jayhendren Oct 01 '18 at 15:54
  • @jayhendren Thanks, I missed that one in the noice. It does not document how to pull the username from the key tho, so I think I'll stay with "withCredentials" for now – Samuel Åslund Oct 02 '18 at 11:51