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

mat*_*ked 10 groovy jenkins

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

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

我试图找到合适的解决方案(例如,在Jenkins构建步骤(Windows)中从Groovy脚本中访问构建环境变量的解决方案)但似乎它们都不适用于我.

我试过例如:

System.getenv("myVar")
Run Code Online (Sandbox Code Playgroud)

manager.build.getEnvironment(listener).get('myVar') //no manager error
Run Code Online (Sandbox Code Playgroud)

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

import jenkins.model.Jenkins
Jenkins.instance.ParameterValue("DEV_local")
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 14

它并不像您想象的那么简单,就像 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))
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

getCombinedNodeEnvironment('').SOME_ENV_VAR_ON_MASTER
Run Code Online (Sandbox Code Playgroud)

相关课程:

现有答案存在问题

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

至少应该读作

jenkins.instance.Jenkins.instance.
   getGlobalNodeProperties().
   get(hudson.slaves.EnvironmentVariablesNodeProperty).
   getEnvVars() 
Run Code Online (Sandbox Code Playgroud)

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

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

请继续阅读。

如果可能的话保持简单

如果您使用 Groovy Pipeline,大多数时候您可以只使用env“变量”(请参阅​​管道帮助中的“全局变量参考”),它将统一环境公开为属性。如上所述,这不能直接从脚本控制台运行,但在其余时间,这是执行操作的适当方法。

您还可以env.getEnvironment()在管道脚本中使用来获取统一实例EnvVars,该实例用于字符串中环境变量的占位符替换,例如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()
}
Run Code Online (Sandbox Code Playgroud)

nodes现在包含jenkins.model.Jenkins主节点和hudson.model.Node工作节点。

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

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

在同一位置的主节点条目上,我已经配置MASTER_SPECIFIC_ENVVAR

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

我没有费心在 JVM 级别为节点和主节点设置自定义环境变量。

对环境的不同看法

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

JVM级别的环境变量(主)

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

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

/* 
master:
    [HOME, JENKINS_HOME, PATH, SHELL, USER]
*/
Run Code Online (Sandbox Code Playgroud)

因此,每个节点、詹金斯本身或每个作业都没有配置任何配置。

节点基础环境

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]
*/
Run Code Online (Sandbox Code Playgroud)

请注意 Jenkins 中缺少全局或特定于节点的环境变量设置。

全局配置的环境变量

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

/*
master getGlobalNodeProperties
----
master:
    [ALL_NODES_ENVVAR]
*/
Run Code Online (Sandbox Code Playgroud)

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

节点特定环境变量覆盖

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

/*
master:
    [MASTER_SPECIFIC_ENVVAR]
ci-node-qa-fsn1-01:
    [NODE1_SPECIFIC_ENVVAR]
*/
Run Code Online (Sandbox Code Playgroud)

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

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

把它放在一起

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

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

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

首先,收集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]
 */
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这是非常丰富的信息并且写得很好。感谢您为此付出的努力。:) (3认同)

ara*_*sio 11

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

def envVars = Jenkins.instance.getGlobalNodeProperties()[0].getEnvVars() 
println envVars['myVar']
Run Code Online (Sandbox Code Playgroud)

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

  • java.lang.NullPointerException:无法在空对象上调用方法getEnvVars() (3认同)