Jenkins: env in pipeline from Jenkinsfile is null - jenkins

Please help. env is null.
Jenkinsfile:
node {
println "Your ENV:"
println env.dump
println "Your params:"
println params.dump
}
Jenkins output:
[Pipeline] properties
[Pipeline] node
Running on foobarquux in c:\workspace\123abc
[Pipeline] {
[Pipeline] echo
Your ENV:
[Pipeline] echo
null
[Pipeline] echo
Your params:
[Pipeline] echo
null
I expect that my environment variables will not be null. I expect env.dump not to be null and to see something beyond Your ENV: when println env.dump executes.
After reading very helpful comments from #mkobit, I realized I needed parentheses for dump, and even with them Jenkins throws a security exception.

${WORKSPACE} only works if it is used in an agent (node)! Otherwise it comes out as null.
I have agent none at the top of my pipeline because I have a few input steps that i don't want use heavyweight executors for. And I was setting an environment variable in the top-level environment {} block that used ${WORKSPACE}. For the life of me I couldn't figure out why it was being set to null. Some other thread mentioned the workspace on an agent, so i moved that definition into a step on an agent, and lo and behold, when you set a var with WORKSPACE while running on an agent, it all works as expected.
The sidebar here is that if you are using a top-level agent none, the environment and presumably other pre-stages blocks are not running in an agent. So anything that relies on an agent will behave unexpectedly.

Groovy's optional parenthesis requires at least one parameter, which is different than Ruby.
Method calls can omit the parentheses if there is at least one parameter and there is no ambiguity:
So, to call the dump() method you would do env.dump() or params.dump(). However, this method will not be whitelisted and you will get a security exception (if you are running in the sandbox or using any sort of Jenkins security) because this would print out all fields of the object.

Thanks to StephenKing for pointing out, i check again with a new fresh Jenkins instance. see comments inside
Assuming the job has 2 parameters [str1=val1, bool1=true] :
node {
// Print the value of a job parameter named "str1"
// output: val1
println "${params.str1}"
// Calling the dump() function to print all job parameters (keys/vals)
// NOTE: calling this method should be approved by Jenkins admin
// output: .... m=[str1:val1, bool1:true] ...
println params.dump()
// Same as the above.
// output: .... m=[str1:val1, bool1:true] ...
println "${params.dump()}"
// SYNTAX ERROR, the '$' is not expected here by the parser
//println ${params.dump()};
// This appears in the question, but it seems like this is not
// what the author meant. It tries to find a param named "dump"
// which is not available
// output: null
println params.dump
}

Related

Jenkins pipeline error in handling json file

I'm newbie to Jenkins pipeline and writing a groovy script to parse a json file. However I'm facing an error which many have faced but none of the solutions worked for me. Below is my Jenkinsfile and error msg.
def envname = readJSON file: '${env.WORKSPACE}/manifest.json'
pipeline {
agent any
stages {
stage('Build') {
steps {
echo WORKSPACE
sh "ls -a ${WORKSPACE}"
}
}
}
}
[Pipeline] Start of Pipeline
[Pipeline] readJSON
[Pipeline] End of Pipeline
org.jenkinsci.plugins.workflow.steps.MissingContextVariableException:
Required context class hudson.FilePath is missing Perhaps you forgot
to surround the code with a step that provides this, such as: node at
org.jenkinsci.plugins.pipeline.utility.steps.AbstractFileOrTextStepExecution.run(AbstractFileOrTextStepExecution.java:30)
I even tried readJSON file: '${WORKSPACE}/manifest.json but that didn't work too. I'm sure the mistake is with the first line since when removing that line, there execution is successful. The docs are pretty helpful but I'm not able to track down where exactly I'm going wrong that is why posted here.
UPDATE:
I tried the following methods def envname = readJSON file: "./manifest.json" and def envname = readJSON file: "${env.WORKSPACE}/manifest.json" and even tried them defining under the steps block. Nothing worked. Below is the error msg I recieved when I defined them under step block
WorkflowScript: 5: Expected a step # line 7, column 13
def envname =
^
Below is the official syntax doc of readJson and I can see that I'm using the correct syntax only. but still doesn't work as expected.
https://www.jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#readjson-read-json-from-files-in-the-workspace
'${env.WORKSPACE}/manifest.json' is interpolating the Groovy env map as a shell variable. You need to interpolate it as a Groovy variable like "${env.WORKSPACE}/manifest.json".
sh "ls -a ${WORKSPACE}" is interpolating the shell environment variable WORKSPACE as a Groovy variable. You need to interpolate it as a shell variable like sh 'ls -a ${WORKSPACE}'.
echo WORKSPACE is attempting to resolve the shell variable WORKSPACE as a first class Groovy variable expression. You need to use the Groovy env map instead like echo env.WORKSPACE.
As for the global variable indefinite type assignment on the first line: if it still throws the error above after making those fixes, then it may be due to invalid use of scripted syntax in a declarative syntax pipeline. You likely need to place it inside a step block within your pipeline in that case.
I've solved this myself with the help of "Matt Schuchard"'s below answer. I'm not sure whether this is the only way to solve but this worked for me.
pipeline {
agent any
stages {
stage('Json-Build') {
steps {
script {
def envname = readJSON file: "${env.WORKSPACE}/manifest.json"
element1 = "${envname.dev}"
echo element1
}
}
}
}
}

Jenkins doesn't fully resolve variables values

I have a Jenkinsfile where I want to declare some variables to later use in other sections. I know about Jenkins use the Groovy syntax rules for variable expansion but I expected some variable values where fully resolved. Instead I found that they just resolved in one level. Code inlcuded below shows what I want: Trying to use $PATHTOFILES variable to link data downloaded/generated in previous stages for a Docker container. Instead the variable is just resolved as pwd.
I tried several options seeking to expand the values that I need, so far unsuccessfully.
agent none
environment {
...
PATHTOFILES = "`pwd`"
...
}
...
stage('Unit'){
agent {
docker {
image "${DOCKERIMAGEURI}"
args '-v $PATHTOFILES:$CONTAINER_DATA_PATH'
}
}
}
Logs show that a value '-v `pwd`:/some/valid/path' is used as argument, leading to an error. Any ideas?
You did wrong to get current workspace of job. One of below 3 methods should work:
1) use shell cmd: pwd and pipeline step: sh() together
PATHTOFILES = sh(script: 'pwd', returnStdout:true).trim()
2) use pipeline step: pwd()
PATHTOFILES = pwd()
3) use environment variable: WORKSPACE
PATHTOFILES = env.WORKSPACE

Attempting to access file system from jenkinsfile

I'm trying to access the file system from a Jenkinsfile using groovy. I'm following the suggestion in this SO thread:
Recursive listing of all files matching a certain filetype in Groovy
I've already given access to
new java.io.File java.lang.String
staticField groovy.io.FileType FILES
under Script Approvals.
However this line is failing without an error message:
new File('.').eachFileRecurse(FILES) {
Here's the broader code block in question:
stage("Install") {
print "here a"
new File('.').eachFileRecurse(FILES) {
print "here c"
if(it.name.endsWith(".sh")) {
print "here d"
println it
}
}
print "here b"
Here's the console output from that section:
[Pipeline] stage
[Pipeline] { (Install)
[Pipeline] echo
here a
[Pipeline] }
[Pipeline] // stage
[Pipeline] echo
Email Recipients: opike99#gmail.com, opike#yahoo.com
[Pipeline] emailext
messageContentType = text/html; charset=UTF-8
Adding recipients from project recipient list
Adding recipients from trigger recipient list
Setting In-Reply-To since last build was not successful
Better use the findFiles step, instead of the Java API to read files. This is whitelisted by script security.
each loops don't work in pipeline because of Jenkins' CPS. Instead (if you really prefer it over good old for loops), wrap it in a method annotated with #NonCPS.

Hiding password in Jenkins pipeline script

I'm trying to mask a password in my Jenkins build.
I have been trying the mask-passwords plugin.
However, this doesn't seem to work with my Jenkins pipeline script, because if I define the password PASSWD1 and then I use it in the script like this ${PASSWD1}, I am getting:
No such DSL method '$' found among steps [addToClasspath, ansiColor, ansiblePlaybook, ....]
If I use env.PASSWD1, then its value will be resolved to null.
So how should I mask a password in a Jenkins pipeline script?
The simplest way would be to use the Credentials Plugin.
There you can define different types of credential, whether it's a single password ("secret text"), or a file, or a username/password combination. Plus other plugins can contribute other types of credentials.
When you create a credential (via the Credentials link on the main Jenkins page), make sure you set an "ID". In the example below, I've called it my-pass. If you don't set it, it will still work, Jenkins will allocate an opaque UUID for you instead.
In any case, you can easily generate the required syntax with the snippet generator.
withCredentials([string(credentialsId: 'my-pass', variable: 'PW1')]) {
echo "My password is '${PW1}'!"
}
This will make the password available in the given variable only within this block. If you attempt to print the password, like I do here, it will be masked.
Looking at this issue, https://issues.jenkins-ci.org/browse/JENKINS-27392, you should be able to do the following:
node {
wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
echo env['SECRET'];
}
}
However, if you look at the last comments in that issue it doesn't work, seems like a bug. However, if you know the secret and accidentally print int in the logs, the it is hidden, like this:
node {
wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
echo "123ADS";
}
}
This produces:
[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] wrap
[Pipeline] {
[Pipeline] echo
********
[Pipeline] }
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Regarding the error you are getting, No such DSL method '$' found among steps ..., I'm just guessing but you are probably using ${VAR} directly in the pipeline script, ${...} is only relevant inside strings in groovy.
EDIT:
Or you can use the Credentails Plugin and pipeline step withCredentials:
// Credential d389273c-03a0-45af-a847-166092b77bda is set to a string secret in Jenkins config.
node {
withCredentials([string(credentialsId: 'd389273c-03a0-45af-a847-166092b77bda', variable: 'SECRET')]) {
bat """
if ["${SECRET}"] == ["123ASD"] echo "Equal!"
""";
}
}
This results in:
[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] bat
[pl] Running batch script
workspace/pl>if ["****"] == ["****"] echo "Equal!"
"Equal!"
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Note that this plugin binds the variable directly to the closure and not the environment as the other, e.g. I can use the variable SECRET directly.

Jenkins Global environment variables in Jenkinsfile

How do I invoke Global environment variables in Jenkinsfile?
For example, if I have a variable -
name:credentialsId
value:xxxx-xxxx-xxxxx-xxxxxxxxx
How do I use it in the groovy script?
I tried ${credentialsId}, but it didn't work. It will just give error:
java.lang.NoSuchMethodError: No such DSL method '$' found among steps [ArtifactoryGradleBuild, ........
In a Jenkinsfile, you have the "Working with the Environment" which mentions:
The full list of environment variables accessible from within Jenkins Pipeline is documented at localhost:8080/pipeline-syntax/globals#env,
The syntax is ${env.xxx} as in:
node {
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
}
See also "Managing the Environment".
How can I pass the Global variables to the Jenkinsfile?
When I say Global variables - I mean in
Jenkins -> Manage Jenkins -> Configure System -> Global properties -> Environment variables
See "Setting environment variables"
Setting an environment variable within a Jenkins Pipeline can be done with the withEnv step, which allows overriding specified environment variables for a given block of Pipeline Script, for example:
Jenkinsfile (Pipeline Script)
node {
/* .. snip .. */
withEnv(["NAME=value"]) {
... your job
}
}
When referring to env in Groovy scope, simply use env.VARIABLE_NAME, for example to pass on BUILD_NUMBER of upstream job to a triggered job:
stage ('Starting job') {
build job: 'TriggerTest', parameters: [
[$class: 'StringParameterValue', name: 'upstream_build_number', value: env.BUILD_NUMBER]
]
}
Scripted pipeline
To read an environment variable whose name you know, use env.NAME
To read an environment variable whose name is not known until runtime use env.getProperty(name).
For example, a value from a YAML config file represents an environment variable name:
config.yaml (in workspace)
myconfig:
key: JOB_DISPLAY_URL
Jenkinsfile
node {
println("Running job ${env.JOB_NAME}")
def config = readYaml(file:'config.yaml')
def value = env.getProperty(config.myconfig.key)
println("Value of property ${config.myconfig.key} is ${value}")
}
For getting values all env.VAR, env['VAR'], env.getProperty('VAR') are fine.
For setting values the only safe way at the moment is withEnv. If you try to assign values to env.VAR it may not work in some cases like for parallel pipelines (like in JENKINS-59871).
Another syntax is $ENV:xxxx
node {
echo "Running $ENV.BUILD_ID on $ENV.JENKINS_URL" }
This worked for me

Resources