首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在“`options`”块中使用`NODE_NAME`?- Jenkinsfile声明管道

如何在“`options`”块中使用`NODE_NAME`?- Jenkinsfile声明管道
EN

Stack Overflow用户
提问于 2022-05-05 05:49:07
回答 1查看 205关注 0票数 0

问:如何在NODE_NAME块中使用options

我尝试过简单地尝试使用env.NODE_NAME的天真解决方案,但这会在options块中计算为null

代码语言:javascript
运行
复制
options { lock(resource: "${env.NODE_NAME}") }

Jenkins管道文档解释了为什么这不起作用:

stage中,在输入agent或检查任何when条件之前调用options指令中的步骤。

因此,在这个上下文中,它被设置为null

接下来,我尝试了各种方法来获得env.NODE_NAME级别的stage { steps {}},并通过一个全局Groovy变量传递它。然而,这似乎不起作用。

在下面的示例Jenkinsfile中,全局Groovy变量GLOBAL_NODE_NAME的作用就好像它是每个stepsstepscript块中的局部变量一样。同时,它的作用就好像它是pipeline { stage { options {} }}块中的一个全局变量。节点“重量级执行器”上下文中设置的值不会冒泡到全局Groovy脚本级别。

我想做的是:

我想在一个lockable-resources块中使用lock插件的lock语法来限制并发作业。如果多个作业运行parallel "Run Tests“阶段,那么所有RAM都会在Jenkins代理节点上使用。因此,我试图锁定每个节点的资源,以限制这个特定节点上的并发作业。

我使用的最小Jenkinsfile如下所示:

代码语言:javascript
运行
复制
String GLOBAL_NODE_NAME = 'GLOBAL'
pipeline {
    agent { label 'ec2-node' }

    stages {
        stage('Get Node Name') {
            steps {
                script {
                    println("env.NODE_NAME='${env.NODE_NAME}'")
                    GLOBAL_NODE_NAME = NODE_NAME
                    println("GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
                }
            }
        }
        stage('Build') {
            steps {
                script {
                    println("DEBUG Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
                    println("DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='" + GLOBAL_NODE_NAME + "'")
                }
                sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
                // Do build steps here
            }
        }

        stage('Run Tests') {
            // Inverse order LIFO
            options {
                // Get NODE_NAME from the currentBuild b/c lightweight executor returns 'null'
                lock(inversePrecedence: true, resource: "${GLOBAL_NODE_NAME}")
            }
            parallel {
                stage('Unit Tests') {
                    steps {
                        echo "Inside Steps block: GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
                        script {
                            println("DEBUG Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
                            println("DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='" + GLOBAL_NODE_NAME + "'")
                        }
                        sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"

                        // Do Unit Tests
                    }
                }

                stage('Integration Tests') {
                    steps {
                        sh 'echo this so example Jenkinsfile is valid'
                        // Do Integration Tests
                    }
                }
            } // end parallel
        }  // end Run Tests
    } // end stages
} // end pipeline

上述示例作业的输出:

  • 舞台:Get Node Name
代码语言:javascript
运行
复制
- `env.NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
  • 舞台:Build
代码语言:javascript
运行
复制
- `DEBUG Interpolation GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
-   echo Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) -  Pipeline Builder (i-feeb1ec0de5caff01d)   Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)
  • 舞台:Run Tests
代码语言:javascript
运行
复制
- **Note:** Inside `options` block, `echo`, `println`, are not available... but we can see the output in the resource's name on the `https://<jenkins-host-here>/lockable-resources/` page: 
    - `GLOBAL_NODE_NAME` is set to "`GLOBAL`", so the `stage` => `step` assignment did **not** work!
    - ​

代码语言:javascript
运行
复制
    - **Lockable Resources shows that the value of** **`resource`** **is still set to** **`GLOBAL`****!**
代码语言:javascript
运行
复制
- Parallel Stage: `Unit Tests` 
    - `Inside Steps block: GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
    - `DEBUG Interpolation GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
    - `DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
    -     + echo Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)     Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)

编辑:这是最后的工作解决方案

多亏了@AdamSmith的回答,它让我开始朝着正确的方向前进。下面是工作的最终Jenkinsfile结构的框架:

代码语言:javascript
运行
复制
/* groovylint-disable DuplicateStringLiteral */
/* groovylint-disable-next-line CompileStatic */
String debugBegin = '============================== DEBUG ENV =============================='
String debugEnd = '============================== END DEBUG =============================='
/* groovylint-disable NestedBlockDepth */
/* groovylint-disable-next-line CompileStatic */
pipeline {
    agent { label 'ec2-node' }

    stages {
        stage('Build') {
            steps {
                script {
                   // Evaluates in 'heavyweight' executor context
                    println("Running on env.NODE_NAME='${env.NODE_NAME}'") // env.NODE_NAME works here
                }
                // Do build steps here
            }
        }

        stage('Run Tests') {
            options {
                /*
                Note: Cannot get NODE_NAME from this context!
                options is evaluated inside 'lightweight' executor, so currentBuild returns 'null'
                and any other method trying to pass env.NODE_NAME, or
                NODE_NAME up from the node / 'heavyweight' executor context did not work!

                lock(inversePrecedence: true, resource: "cannot-get-node-name") // Anything I tried here did not work!
                This context executes on jenkins master, and I could not find a way to pass the value back from a node
                */
                timeout(time: 15, unit: 'MINUTES')
            }
            steps {
                // Inverse order LIFO
                // lock NODE_NAME b/c parallel tests are RAM intensive
                lock(inversePrecedence: true, resource: "${NODE_NAME}") {
                    script { // hack so parallel syntax is made available here
                        parallel Test: { // map: {} syntax to pass to scripted-pipeline 'parallel'
                            stage('Test') {
                                try { // Switched from post { always {}} to => try {} finally {} here
                                    // because syntax did not work otherwise
                                    echo "Inside Steps block: NODE_NAME='${NODE_NAME}'"
                                    println("DEBUG Interpolation NODE_NAME='${NODE_NAME}'")
                                    println("DEBUG Raw Groovy Variable NODE_NAME='" + NODE_NAME + "'")
                                    sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${NODE_NAME}'"
                                    echo "${debugBegin}"
                                    sh 'env' // STAGE_NAME is now 'Test'
                                    echo "${debugEnd}"
                                    sh 'make test'
                                    echo 'Tests Succeeded!'
                                }
                                finally {
                                    junit '**/path/to/test-reports/*.xml'
                                    sh 'make cleanup'
                                }
                            }
                        },
                        IntegrationTests: {
                            stage('Integration Tests') {
                                try {
                                    echo "${debugBegin}"
                                    sh 'env' // STAGE_NAME is now 'Integration Tests'
                                    echo "${debugEnd}"
                                    sh 'make integration'
                                    echo 'Integration Tests Succeeded!'
                                }
                                finally {
                                    sh 'make cleanup'
                                }
                            }
                        } // end parallel map
                    } // end script
                } // end lock NODE_NAME
            } // end steps
        } // end stage Run Tests
    } // end stages
} // end pipeline
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-05 06:01:55

您不能这样做,但是由于lock也可以在steps块中使用,所以您可以这样处理它。由于这些事情的性质,您可能需要在这里使用一个script转义程序来继续并行(对不起)

代码语言:javascript
运行
复制
stage('Run Tests') {
    steps {
        // Inverse order LIFO
        lock(inversePrecedence: true, resource: "${NODE_NAME}") {
            script {
                parallel [
                    'Unit Tests': {
                        echo "Inside Steps block: NODE_NAME='${NODE_NAME}'"
                        println("DEBUG Interpolation NODE_NAME='${NODE_NAME}'")
                        println("DEBUG Raw Groovy Variable NODE_NAME='" + NODE_NAME+ "'")
                        sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
                    },
                    'Integration Tests': {
                        sh 'echo this so example Jenkinsfile is valid'
                    }
                ]
            } // end script
        } // end lock
    }  // end steps
} // end stage 'Run Tests'
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72122472

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档