詹金斯管道/ Groovy脚本与未定义的变量 [英] Jenkins Pipeline / Groovy Script with undefined variables

查看:231
本文介绍了詹金斯管道/ Groovy脚本与未定义的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将我的大型多配置Jenkins作业转换为流水线语法,以便我可以将其分割成多个节点,并将我的多个阶段合并为一个作业。这里是我看到麻烦的部分:

  def build_test_configs = [:] 
def compilers = ['gnu ','icc']
def configs = ['debug','default','opt']

for(int i = 0; i< configs.size(); ($ {
for(int j = 0; j< compilers.size(); j ++){
def node_name =
if($ {compilers [j]} ==gnu){
node_name =node001
} else {
node_name =node002
}
build_test_configs [$ {node_name} $ { configs [i]}] = {
node($ {node_name}){
stage(Build Test $ {node_name} $ {compilers [j]} $ {configs [i]} ){
unsash$ {node_name} -tarball
sh$ HOME / software / jenkins_scripts / nightly.sh $ {configs [i]} $ {compilers [j]} yes $ WORKSPACE
}
}
}
}
}

并行build_test_configs
code>

我的问题是 $ {compilers [j] 和<$ c当我到达想要构建 build_test_configs 字典的部分时,$ c> $ configs [i] 未定义13.看起来第8行的检查工作正常。



更新



我不'本身没有错误信息。该脚本不会产生任何运行时错误。意外的输出是这些阶段的名称是:

$ ul

  • 构建测试node001 null null
  • 生成测试node001 null null
  • 生成测试node002 null null



  • nightly.sh 脚本获得通过 null 参数。

    解决方案

    我认为这是预期的行为:Jenkins管道脚本是用Groovy编写的,但实际执行的是对其的转换(他们使用的术语是continuation-passing style transformation)。例如,一些零件会在主人身上运行,一些在奴隶人的节点上运行。



    这涉及到很多可以飞到我头上的魔法,但在我们的水平上它意味着我们必须在语法&我们使用的结构。



    参见本文的基本面部分


    要理解管道行为,您必须了解





    1. 除了步骤本身外,所有的流水线逻辑,
      Groovy条件,循环等在master上执行。无论
      简单还是复杂!甚至在节点块内!
    2. 步骤可以使用执行程序在适当的地方进行工作,但每个步骤也都有一个小的开销控制开销。

    3. 管道代码编写为Groovy,但执行
      模型在编译时从根本上转换为延续
      传递样式(CPS)。
    4. 这个转换提供了有价值的安全性
      和Pipelines的持久性保证,但它带有
      的权衡:步骤可以调用Java并快速高效地执行,
      ,但Groovy比正常运行慢得多。 Groovy逻辑需要
      更多的内存,因为基于对象的语法/块树在内存中保持

    5. Pipelines将程序及其状态频繁地保存到$


      另请参阅 JENKINS-41335 讨论跨越脚本的变量支持。

      编辑:啊,是的,正如评论中指出的那样,新的声明模型允许定义环境,变量将以您需要的方式传递......不知道如何在没有JENKINS-41335的脚本管道中执行此操作,但似乎进一步的演变将在声明式土地中发生:/


      I'm trying to convert my large multi-config Jenkins job over to pipeline syntax so I can, among other things, split it across multiple nodes and combine my multiple stages into one job. Here's the part where I'm seeing trouble:

      def build_test_configs = [:]
      def compilers = ['gnu', 'icc']
      def configs = ['debug', 'default', 'opt']
      
      for (int i = 0; i < configs.size(); i++) {
          for (int j = 0; j < compilers.size(); j++) {
              def node_name = ""
              if ("${compilers[j]}" == "gnu") {
                  node_name = "node001"
              } else {
                  node_name = "node002"
              }
              build_test_configs["${node_name} ${configs[i]}"] = {
                  node ("${node_name}") {
                      stage("Build Test ${node_name} ${compilers[j]} ${configs[i]}") {
                          unstash "${node_name}-tarball"
                          sh "$HOME/software/jenkins_scripts/nightly.sh ${configs[i]} ${compilers[j]} yes $WORKSPACE"
                      }
                  }
              }
          }
      }
      
      parallel build_test_configs
      

      My problem is that ${compilers[j] and $configs[i] are undefined when I get to the part where I'm trying to build up a dictionary of build_test_configs on line 13. It would appear that the check on line 8 is working just fine.

      Update

      I don't have an error message per se. The script doesn't produce any runtime errors. The unexpected output is that the names of the stages are:

      • Build Test node001 null null
      • Build Test node001 null null
      • Build Test node002 null null

      And the nightly.sh script is getting passed null parameters as well.

      解决方案

      I think this is the expected behavior: Jenkins Pipeline scripts are written in Groovy but what is actually executed is a transformation of that (the term they use is "continuation-passing style transformation"). For example, some parts will run on the master, some on the slave nodes.

      This involves a lot of magic that flies way above my head, but at our level it means we have to work with constraints in the syntax & constructs we use.

      See the "fundamentals" paragraph of this article:

      To understand Pipeline behavior you must understand a few points about how it executes.

      1. Except for the steps themselves, all of the Pipeline logic, the Groovy conditionals, loops, etc execute on the master. Whether simple or complex! Even inside a node block!
      2. Steps may use executors to do work where appropriate, but each step has a small on-master overhead too.
      3. Pipeline code is written as Groovy but the execution model is radically transformed at compile-time to Continuation Passing Style (CPS).
      4. This transformation provides valuable safety and durability guarantees for Pipelines, but it comes with trade-offs: Steps can invoke Java and execute fast and efficiently, but Groovy is much slower to run than normal. Groovy logic requires far more memory, because an object-based syntax/block tree is kept in memory.
      5. Pipelines persist the program and its state frequently to be able to survive failure of the master.

      Also see JENKINS-41335 discussing support of variables across the script.

      Edit: ah, yes, as pointed in the comments, the new declarative model allows to define an environment with variables that would be passed the way you need... Don't know how to do that in scripted pipeline without JENKINS-41335 but it seems further evolutions will now happen in declarative land :/

      这篇关于詹金斯管道/ Groovy脚本与未定义的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆