如何在Jenkins Groovy脚本控制台中获取环境变量?

时间:2016-10-24 09:52:03

标签: jenkins groovy

在Jenkins配置中(http://JenkinsURL/configure)"全局属性"我定义了一些"环境变量"。

如何在Groovy Script控制台(http://JenkinsURL/script)中访问它们?

我试图找到合适的解决方案(例如:Access to build environment variables from a groovy script in a Jenkins build step (Windows)中提到的解决方案) 但似乎它们都不适合我。

我已尝试过例如:

System.getenv("myVar")

manager.build.getEnvironment(listener).get('myVar') //no manager error

import jenkins.model.Jenkins
Jenkins.instance.getProperty('myVar') //No signature of method: hudson.model.Hudson.getProperty() is applicable for argument types: (java.lang.String)

import jenkins.model.Jenkins
Jenkins.instance.ParameterValue("DEV_local")

4 个答案:

答案 0 :(得分:9)

您可以获得以下全局属性:

def envVars = Jenkins.instance.getGlobalNodeProperties()[0].getEnvVars() 
println envVars['myVar']

我参考了下面的链接,关于如何以编程方式设置全局属性。 https://groups.google.com/forum/#!topic/jenkinsci-users/KgCGuDmED1Q

答案 1 :(得分:1)

它并不像您想象的那么简单,就像 Jenkins 中的一切一样。它似乎没有公开一个简单的 API 来获取当前执行上下文的最终有效环境,至少没有暴露给脚本控制台。

最终配方

这是您可以直接使用的打包版本,或者您可以稍作修改以捆绑到管道全局库中的 vars/ 类中。

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

用法:

getCombinedNodeEnvironment('somenode').expand('$JENKINS_HOME/$USER/$SOME_NODE_VARIABLE')

getCombinedNodeEnvironment('').SOME_ENV_VAR_ON_MASTER

相关类:

现有答案的问题

arasio 的回答是一个好的开始,但假设 envvars 属性将位于全局属性的索引 0 是不正确的。该方法还会忽略在特定节点上本地设置的环境变量。

至少应该阅读

jenkins.instance.Jenkins.instance.
   getGlobalNodeProperties().
   get(hudson.slaves.EnvironmentVariablesNodeProperty).
   getEnvVars() 

即在 DescribableList 结果中按类查找属性,而不是假设索引。

但是,只能从全局 jenkins 配置中的“环境变量”列表中获取环境变量 - 它不会显示系统环境变量,也不会显示特定于节点的环境变量。

继续阅读。

尽量简单

如果您使用的是 Groovy 管道,大多数情况下您可以只使用 env "variable"(请参阅管道帮助中的“全局变量引用”),它将统一环境公开为属性。如上所述,这不能直接从脚本控制台工作,但在其他时候,它是做事的合适方式。

您还可以在流水线脚本中使用 env.getEnvironment() 来获得统一的 EnvVars 实例,用于字符串中 env-vars 的占位符替换,例如env.getEnvironment().expand('${FOO} $BAR')。 (您需要为此获得脚本安全权限,但最好将其放在全局库的 vars/ 中的帮助程序中)。

大多数情况下这就足够了。

我只是深入研究环境结构的细节,因为我需要扩展包含环境变量的字符串因为它们会在不同的节点上扩展。这不是一个常见的用例。

说明它的工作原理和示例设置

这是最后的秘诀,但我们是如何到达那里的,不同的环境变量集从何而来,为什么?

对于下面的代码示例,假设这个共同的前奏,​​主要是为了节省每个示例中的重复。

/* 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 现在包含 jenkins.model.Jenkins 主节点和一个 hudson.model.Node 工作节点。

eachNode 生成节点名称到环境变量键的缩写列表的映射,只是为了使示例更简洁易读。不要在你的代码中使用它。

为了帮助阐明这些示例的结果,我在 node1 的节点设置中的“管理 Jenkins”->“管理节点和云”-> [节点名称] -> 配置 -> 环境下配置了 NODE1_SPECIFIC_ENVVAR变量。

在同一个地方的主节点条目上,我已经配置了MASTER_SPECIFIC_ENVVAR

在“管理Jenkins”->“配置系统”->“全局属性”->“环境变量”中,我添加了“ALL_NODES_ENVVAR”。

我没有费心在 JVM 级别为节点和主节点设置自定义 env-var。

对环境的不同看法

现在,让我们以不同的方式探索环境。

JVM 级环境变量(主)

在 master 上,System.getenv() 仅显示 JVM 启动时设置的环境变量或作为系统属性设置:

fmtEnv('System.getenv()', ['': System.getenv()])

/* 
master:
    [HOME, JENKINS_HOME, PATH, SHELL, USER]
*/

因此没有针对每个节点、全局在 jenkins 本身或每个作业中配置任何内容。

节点基础环境

Jenkins 在其 API 中公开在每个节点上设置的基本环境变量。我认为这与 System.getEnv() 在目标节点 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]
*/

注意 Jenkins 中没有设置全局或节点特定的 env-vars。

全局配置的环境变量

fmtEnv('master getGlobalNodeProperties', ['': 
  Jenkins.instance.
     getGlobalNodeProperties().
     get(EnvironmentVariablesNodeProperty).
     getEnvVars()
])

/*
master getGlobalNodeProperties
----
master:
    [ALL_NODES_ENVVAR]
*/

所以这里我们只能看到全局配置的环境属性,而不是特定于节点的属性、系统属性或主机环境变量。

节点特定的环境变量覆盖

fmtEnv('node getNodeProperty', eachNode() {
  node, name -> node.getNodeProperty(EnvironmentVariablesNodeProperty)?.getEnvVars()
})

/*
master:
    [MASTER_SPECIFIC_ENVVAR]
ci-node-qa-fsn1-01:
    [NODE1_SPECIFIC_ENVVAR]
*/

这里我们看到在“管理节点”中每个节点下配置的属性,但不是主机环境变量、来自系统属性的变量、标准 jenkins 作业变量或在 jenkins 全局配置中配置的变量。

重要:如果节点上没有配置自定义环境变量,getNodeProperty(EnvironmentVariablesNodeProperty) 将返回 null,因此您必须处理它。

把它放在一起

以上显示了如何获取 EnvVars 实例,用于在脚本控制台上有意义的环境变量的主要来源。

运行作业时还有其他来源,我在这里不考虑,例如作业属性(EnvInject 插件)、自动添加到所有作业的 env-vars、withEnvironment 步骤、SCM 插件注入的变量(s) 等。但它们对脚本控制台任务没有意义。

那么我们如何获得统一的环境?

首先,为环境的每个相关部分收集 EnvVars

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]
 */

我很确定这会产生正确的结果。我没有详细测试扩展处理、优先级覆盖顺序或扩展顺序。

(注意:我删除了另一个使用 EnvironmentExpander 的示例)。

答案 2 :(得分:0)

您可以使用System来获取环境变量。

def env = System.getenv()
println(env['JENKINS_HOME'])

(有关内置环境变量的列表,另请参见https://myJenkHostname/env-vars.html。)

答案 3 :(得分:0)

由于“安全”问题,这些答案都不适合我。 而只是使用环境变量的名称,例如您可以使用的环境变量 PATH:

final path = PATH

你也可以使用

final path = env.PATH

很惊讶它是如此简单,但它是......