In Jenkins configuration (http://JenkinsURL/configure) within "Global properties" I defined some "Environment variables".
How can I access them in the Groovy Script console (http://JenkinsURL/script)?
I've tried to find appropriate solution (for example the solutions mentioned in: Access to build environment variables from a groovy script in a Jenkins build step (Windows)) but it seems that none of them work for me.
I've tried for example:
System.getenv("myVar")
and
manager.build.getEnvironment(listener).get('myVar') //no manager error
and
import jenkins.model.Jenkins
Jenkins.instance.getProperty('myVar') //No signature of method: hudson.model.Hudson.getProperty() is applicable for argument types: (java.lang.String)
and
import jenkins.model.Jenkins
Jenkins.instance.ParameterValue("DEV_local")
You can get global properties like this:
import jenkins.model.Jenkins
def envVars = Jenkins.instance.getGlobalNodeProperties()[0].getEnvVars()
println envVars['myVar']
I referred to the link below, about how to set global properties programatically. https://groups.google.com/forum/#!topic/jenkinsci-users/KgCGuDmED1Q
It's not as simple as you'd think, like everything in Jenkins. It doesn't appear to expose a simple API to get the final effective environment for the current execution context, at least not to the script console.
Here's a wrapped up version you can use directly, or you can adapt a little to bundle into a vars/
class in your pipeline global library.
import jenkins.model.Jenkins
import hudson.model.Node
import hudson.slaves.EnvironmentVariablesNodeProperty
import hudson.EnvVars
EnvVars getCombinedNodeEnvironment(Node node) {
/*
* Start with env-vars defined by the shell the JVM
* was started from and env-vars set as system properties.
*/
def combined = new EnvVars(node.toComputer().getEnvironment())
/*
* Apply environment variables from jenkins global settings
* ("Manage Jenkins" -> "Configure System" -> "Global Properties"
* -> "Environment Variables")
*/
combined.overrideExpandingAll(Jenkins.instance.
getGlobalNodeProperties().
get(EnvironmentVariablesNodeProperty).
getEnvVars() ?: new EnvVars())
/*
* Apply environment variables from node specific settings
* ("Manage Jenkins" -> "Manage Nodes and Clouds"
* -> {nodename} -> "Configure" -> "Node Properties"
* -> "Environment Variables")
*/
combined.overrideExpandingAll((node.
getNodeProperty(EnvironmentVariablesNodeProperty)?.
getEnvVars()) ?: new EnvVars())
/*
* Important: This environment map will NOT contain job-level,
* or run-level properties, nor anything set via build steps etc.
*/
return combined
}
EnvVars getCombinedNodeEnvironment(String nodename) {
if (nodename == 'master' || !nodename)
return getCombinedNodeEnvironment(Jenkins.instance)
else
return getCombinedNodeEnvironment(Jenkins.instance.getNode(nodename))
}
Usage:
getCombinedNodeEnvironment('somenode').expand('$JENKINS_HOME/$USER/$SOME_NODE_VARIABLE')
getCombinedNodeEnvironment('').SOME_ENV_VAR_ON_MASTER
Relevant classes:
hudson.model.Node
jenkins.model.Jenkins
hudson.EnvVars
hudson.slaves.EnvironmentVariablesNodeProperty
hudson.util.DescribableList
The answer by arasio is a good start, but it's incorrect to assume the envvars properties will be at index 0 of the global properties. That approach also ignores environment variables set locally on specific nodes.
At minimum it should read
jenkins.instance.Jenkins.instance.
getGlobalNodeProperties().
get(hudson.slaves.EnvironmentVariablesNodeProperty).
getEnvVars()
i.e find the property by class within the DescribableList
result, instead of assuming index.
However, that only gets you env vars from the "Environment Variables" list in the global jenkins configuration - it won't show system environment variables, nor will it show node-specific environment variables.
Read on.
If you're using the Groovy Pipeline, most of the time you can just use the env
"variable" (see "Global Variable Reference" in pipeline help), which exposes the unified environment as properties. As noted above this won't work directly from the script console, but the rest of the time it's the appropriate way to do things.
You can also use env.getEnvironment()
in Pipeline scripts to get a unified EnvVars
instance, which be used for placeholder substitution of env-vars in strings e.g. env.getEnvironment().expand('${FOO} $BAR')
. (You'll need script security permission for this, but it's better to put it in a helper in your global library's vars/
instead).
Most of the time this is sufficient.
I only landed up diving into the details of the environment structure because I needed to expand strings containing environment variables as they would be expanded on a different node. That's not a common use case.
That's the final recipe, but how did we get there, where do the different sets of environment variables come from, and why?
For the following code examples assume this common prelude, mostly to save on repetition in each example.
/* Jenkins uses '' for the master node */
nodenames = ['', 'some-other-node-name']
/* Imports used in various examples */
import jenkins.model.Jenkins
import hudson.slaves.EnvironmentVariablesNodeProperty
import hudson.EnvVars
nodes = nodenames.collect { nodename ->
(!nodename || nodename == 'master') ?
Jenkins.instance : Jenkins.instance.getNode(nodename)
import static groovy.json.JsonOutput.toJson
import static groovy.json.JsonOutput.prettyPrint
def eachNode(Closure c) {
nodes.collectEntries { node -> [node.nodeName, c(node, node.nodeName) ] }
def fmtEnv(desc,m) {
print "\n\n${desc}\n----\n" + m.collect { k, v -> "${k?:'master'}:\n\t${trimKeys(v)}" }.join('\n')
}
def trimKeys(l) {
if (l == null)
return l
if (l in Map)
l = l.keySet()
l = l - ['_', 'OLDPWD', 'PWD', 'SSH_CLIENT', 'JAVA_HOME', 'LANG', 'LOGNAME', 'MAIL', 'MANPATH', 'S_COLORS', 'SHLVL', 'XDG_RUNTIME_DIR', 'XDG_SESSION_ID']
l.sort()
}
nodes
now contains the jenkins.model.Jenkins
master and a hudson.model.Node
worker node.
eachNode
produces a Map of node name to abbreviated list of environment variable keys, just to make the examples briefer and easier to read. Don't use it in your code.
To help clarify the results of these examples, I have configured NODE1_SPECIFIC_ENVVAR
in the node setup for node1 under "Manage Jenkins" -> "Manage Nodes and Clouds" -> [nodename] -> Configure -> Environment Variables.
On the master node entry in the same place, I have configured MASTER_SPECIFIC_ENVVAR
In "Manage Jenkins" -> "Configure System" -> "Global Properties" -> "Environment Variables" I added "ALL_NODES_ENVVAR".
I didn't bother setting custom env-vars at the JVM level for the node and master.
Now, lets explore the environment different ways.
On master, System.getenv()
shows only env vars set when the JVM started or as system properties:
fmtEnv('System.getenv()', ['': System.getenv()])
/*
master:
[HOME, JENKINS_HOME, PATH, SHELL, USER]
*/
so nothing configured per-node, globally in jenkins itself, or per-job.
Jenkins exposes the base environment variables set on each node in its API. I think this is the same as System.getEnv()
would return when executed on the target node JVM:
fmtEnv('toComputer.getEnvironment()', eachNode() {
node, name -> node.toComputer().getEnvironment()
})
/*
master:
[HOME, JENKINS_HOME, PATH, SHELL, USER]
ci-node-qa-fsn1-01:
[HOME, PATH, SHELL, SSH_CONNECTION, USER]
*/
Note the absence of global or node-specific env-vars set in Jenkins.
fmtEnv('master getGlobalNodeProperties', ['':
Jenkins.instance.
getGlobalNodeProperties().
get(EnvironmentVariablesNodeProperty).
getEnvVars()
])
/*
master getGlobalNodeProperties
----
master:
[ALL_NODES_ENVVAR]
*/
So here we see only the globally configured environment properties, not node-specific properties, system properties, or host environment vars.
fmtEnv('node getNodeProperty', eachNode() {
node, name -> node.getNodeProperty(EnvironmentVariablesNodeProperty)?.getEnvVars()
})
/*
master:
[MASTER_SPECIFIC_ENVVAR]
ci-node-qa-fsn1-01:
[NODE1_SPECIFIC_ENVVAR]
*/
Here we see the properties configured under each node in "manage nodes", but not host env-vars, vars from system properties, standard jenkins job vars, or vars configured in jenkins global config.
Important: getNodeProperty(EnvironmentVariablesNodeProperty)
returns null
if there are no custom environment variables configured on a node, so you must handle that.
The above shows how to get EnvVars
instances for the main sources of environment variables that are meaningful on the script console.
There are other sources when running a job which I don't consider here, such as job properties (EnvInject plugin), automatic env-vars added to all jobs, withEnvironment
steps, vars injected by the SCM plugin(s), etc. But they don't make sense for script console tasks.
So how do we get a unified environment?
First, collect up the EnvVars
for each relevant piece of the environment:
def node_base_env = node.toComputer().getEnvironment()
def global_env_properties = Jenkins.instance.
getGlobalNodeProperties().
get(EnvironmentVariablesNodeProperty).
getEnvVars()
def node_env_properties = node.getNodeProperty(EnvironmentVariablesNodeProperty)?.getEnvVars() ?: new EnvVars()
def merged = new EnvVars(node_base_env)
merged.overrideExpandingAll(global_env_properties)
merged.overrideExpandingAll(node_env_properties)
merged
/*
master:
[ALL_NODES_ENVVAR, HOME, JENKINS_HOME, MASTER_SPECIFIC_ENVVAR, PATH, SHELL, USER]
ci-node-qa-fsn1-01:
[ALL_NODES_ENVVAR, HOME, NODE1_SPECIFIC_ENVVAR, PATH, SHELL, SSH_CONNECTION, USER]
*/
I'm pretty sure that's going to produce the right results. I have not tested the expansion handling, priority override order, or expansion order in detail.
(Note: I removed another example that used EnvironmentExpander
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With