Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the relationship between Environment and Parameters in Jenkinsfile Parameterized Builds?

I recently ran into something of a puzzler while working on some Jenkins builds with a coworker. He's been using params.VARIABLE and env.VARIABLE interchangably and having no issues with it. Meanwhile, I started getting null object errors on one of his calls to a parameter object through the environment on this line of code:

if(!deploy_environments.contains(env.ENVIRONMENT_NAME.trim()) || params.INVOKE_PARAMETERS ) {

ENVIRONMENT_NAME here is a parameter. I started getting this error:

java.lang.NullPointerException: Cannot invoke method trim() on null object

This build is executing as a child of another build. The ENVIRONMENT_NAME parameter is passed down to the child from that parent build.

He was not seeing this error at all on a different Jenkins master. When I changed the reference above from env.ENVIRONMENT_NAME to params.ENVIRONMENT_NAME the issue went away.

I could find no reference to params == env in the Jenkins documentation, so I created a build to try to clarify their relationship.

pipeline {
    agent {
        label 'jenkins-ecs-slave'
    }
    environment {
        ENV_VARIABLE = 'Environment'
    }
    parameters {
        string(description: 'Parameter', name: 'PARAMETER_VARIABLE', defaultValue: 'Parameter')

    }
    stages {
       stage('Output Parameters'){
          steps {
             script {
                 echo "Environment: ${env.ENV_VARIABLE}"
                 echo "Parameter: ${params.PARAMETER_VARIABLE}"
                 echo "Environment from params: ${params.ENV_VARIABLE}"
                 echo "Parameter from Env: ${env.PARAMETER_VARIABLE}"
                 echo "Inspecific reference ENV_VARIABLE: $ENV_VARIABLE"
                 echo "Inspecific reference PARAMETER_VARIABLE: $PARAMETER_VARIABLE"
                 sh 'echo "Shell environment: $ENV_VARIABLE"'
                 sh 'echo "Shell parameter: $PARAMETER_VARIABLE"'                  
             }
           }
       }
    }
}

The first time I ran this on my Jenkins master, it only included the first four lines (echo env.ENV, echo param.PARAM, echo env.PARAM, echo param.ENV) it succeeded with the following output:

[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: null
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

And I thought, "Aha!" Problem solved. They're not the same.

However, that box promptly froze up on me afterwards and refused to queue anymore builds. I haven't finished debugging it, but it's not out of line to wonder if that master is just messed up.

So I went and ran it on a third Jenkins master we have hanging around. It's at this point I added the additional lines you see in the script above to further clarify. The first time I ran this script on that box, it failed on the "Inspecific reference to $PARAMETER_VARIABLE line" with the following output:

[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: null
[Pipeline] echo
Inspecific reference ENV_VARIABLE: Environment
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: PARAMETER_VARIABLE for class: groovy.lang.Binding

Okay, so far so good. This makes sense. They aren't the same. You can reference Environment variables in echos and shells with out specifically referencing the environment object, but can't do the same with parameters. Consistent, reasonable, I'm good with this.

So then I removed the two lines doing the "inspecific reference" and the script succeeded with the following output:

[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: Parameter
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell environment: Environment'
Shell environment: Environment
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell parameter: Parameter'
Shell parameter: Parameter
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

And now I'm completely confuddled. What the hell? I ran it a couple of times just to be sure, and got the same successful output as above, consistently.

Granted, none of the previous builds that showed env.PARAM as null had really succeeded in a clean environment (the one that succeeded was in an environment the promptly imploded on me afterwards). So maybe if there's an error in the Jenkins pipeline, it short circuits the loading of parameters into the environment or something? I tried adding echo "$I_SHOULD_FAIL" to the script to force an error in an attempt to reproduce what was I seeing. No dice:

[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: Parameter
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell environment: Environment'
Shell environment: Environment
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell parameter: Parameter'
Shell parameter: Parameter
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: I_SHOULD_FAIL for class: groovy.lang.Binding

So what's going on here? What's the relationship between environment and parameters in Jenkins pipelines? What is that relationship supposed to be and why does it seem to be inconsistent?

like image 562
Daniel Bingham Avatar asked May 17 '18 18:05

Daniel Bingham


People also ask

Are Jenkins parameters environment variables?

The parameters are available as environment variables. So e.g. a shell ($FOO, %FOO%) or Ant ( ${env. FOO} ) can access these values.

What is build with parameters in Jenkins?

A build parameter allows us to pass data into our Jenkins jobs. Using build parameters, we can pass any data we want: git branch name, secret credentials, hostnames and ports, and so on. Any Jenkins job or pipeline can be parameterized.

What is Jenkins environment variable?

What are Environment Variables in Jenkins? Environment variables are global key-value pairs Jenkins can access and inject into a project. Use Jenkins environment variables to avoid having to code the same values for each project. Other benefits of using Jenkins environment variables include improved security.


1 Answers

Basically this works as follows

  • env contains all environment variables.
  • Jenkins pipeline automatically creates a global variable for each environment variable
  • params contains all build parameters.
  • Jenkins also automatically creates an environment variable for each build parameter (and as a consequence of the second point a global variable).

Environment variables can be overridden or unset, but params is an immutable Map and cannot be changed. Best practice is to always use params when you need to get a build parameter.

See Global Variable Reference for more details regarding the variables.

like image 118
Vitalii Vitrenko Avatar answered Sep 28 '22 00:09

Vitalii Vitrenko