在声明式jenkins管道中 - 我可以动态设置代理标签吗?

Gil*_*ani 22 jenkins jenkins-declarative-pipeline

有没有办法动态设置代理标签而不是普通字符串?

这项工作有两个阶段:

  1. 第一阶段 - 始终在"主"代理上运行.在这个阶段结束时,我将知道第二阶段应该运行哪个代理.
  2. 第二阶段 - 应该在第一阶段确定的代理上运行.

我的(不工作)尝试看起来像这样:

pipeline {
    agent { label 'master' }
    stages {
        stage('Stage1') {
            steps {
                script {
                    env.node_name = "my_node_label"
                }
                echo "node_name: ${env.node_name}"
            }
        }

        stage('Stage2') {
            agent { label "${env.node_name}" }
            steps {
                echo "node_name: ${env.node_name}"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第一个回声工作正常,打印"my_node_label".第二阶段无法在标记为"my_node_label"的代理上运行,控制台将打印:

没有标签为'null'的节点

也许它可以提供帮助 - 如果我只是在标签字段中添加"$ {env}",我可以看到这是一个java类,因为它打印:

没有标有'org.jenkinsci.plugins.workflow.cps.EnvActionImpl@79c0ce06'标签的节点

小智 22

以下是我如何制作它:混合脚本和声明性管道.首先,我使用脚本语法来查找,例如,我正在使用分支.然后定义AGENT_LABEL变量.此var可以在声明性管道的任何位置使用

def AGENT_LABEL = null

node('master') {
  stage('Checkout and set agent'){
     checkout scm
     ### Or just use any other approach to figure out agent label: read file, etc
     if (env.BRANCH_NAME == 'master') {
        AGENT_LABEL = "prod"
     } else {
        AGENT_LABEL = "dev"
     }
   }
}

pipeline {
    agent {
       label "${AGENT_LABEL}"
    }

    stages {
        stage('Normal build') {
           steps {
              echo "Running in ${AGENT_LABEL}"
              sh "hostname"
           }
        } 

        stage ("Docker build") {
           agent{
             dockerfile {
                dir 'Dockerfiles'
                label "${AGENT_LABEL}"
             }
            }
            steps{
                sh "hostname"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以简单地编写“label AGENT_LABEL”,而不是进行字符串插值(`label "${AGENT_LABEL}"`)。 (6认同)
  • 为什么在第一节中使用代理?只需在 `agent` 声明中使用闭包即可: `pipeline { agent { label "${env.BRANCH_NAME.equalsIgnoreCase('master') ? 'prod' : 'dev'}" }` (2认同)

Rob*_*les 13

要查看其工作原理,请使用GString对象执行a println并同时返回agentName的变量.您可以从输出中看到此行在任何其他管道代码之前评估良好.

agentName = "Windows"
agentLabel = "${println 'Right Now the Agent Name is ' + agentName; return agentName}"

pipeline {
    agent none

    stages {
        stage('Prep') {
            steps {
                script {
                    agentName = "Linux"
                }
            }
        }
        stage('Checking') {
            steps {
                script {
                    println agentLabel
                    println agentName
                }
            }
        }
        stage('Final') {
            agent { label agentLabel }

            steps {
                script {
                    println agentLabel
                    println agentName
                }
            }
    }

    }
}
Run Code Online (Sandbox Code Playgroud)

控制台输出(请注意,我实际上没有在此实例上标记为Windows的节点,因此我在找不到它之后中止了):

Started by user Admin
[Pipeline] echo
Right Now the Agent Name is Windows
[Pipeline] stage
[Pipeline] { (Prep)
[Pipeline] script
[Pipeline] {
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Checking)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Windows
[Pipeline] echo
Linux
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Final)
[Pipeline] node
Still waiting to schedule task
There are no nodes with the label ‘Windows’
Aborted by Admin
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
ERROR: Queue task was cancelled
Finished: ABORTED
Run Code Online (Sandbox Code Playgroud)

注意该行在Right Now the Agent Name is Windows输出中很早就出现了.这解释了为什么您的值为null.在脚本修改变量之前很久就会对该语句进行求值.

我可能会尝试使用延迟GString来获取变量.

agentLabel = "${-> println 'Right Now the Agent Name is ' + agentName; return agentName}"
Run Code Online (Sandbox Code Playgroud)

不幸的是,这会引发错误,因为它期待一种String类型.显然它可以将非惰性GString强制转换为String,而不是懒惰版本.因此,当我强制强制转换为String时,当然,它会在那时评估变量(在管道代码实际运行之前再次).

agent { label agentLabel as String }
Run Code Online (Sandbox Code Playgroud)

您可以通过回退到旧节点分配方法来解决问题:

agentName = "Windows"
agentLabel = "${-> println 'Right Now the Agent Name is ' + agentName; return agentName}"

pipeline {
    agent none

    stages {
        stage('Prep') {
            steps {
                script {
                    agentName = "Linux"
                }
            }
        }
        stage('Checking') {
            steps {
                script {
                    println agentLabel
                    println agentName
                }
            }
        }
        stage('Final') {

            steps {
                node( agentLabel as String ) {  // Evaluate the node label later
                    echo "TEST"
                }
                script {
                    println agentLabel
                    println agentName
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以从此控制台输出中看到它现在可以正确找到Linux节点并完成管道.agentName == Windows的早期评估永远不会发生:

Started by user Admin
[Pipeline] stage
[Pipeline] { (Prep)
[Pipeline] script
[Pipeline] {
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Checking)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Right Now the Agent Name is Linux
[Pipeline] echo
Linux
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Final)
[Pipeline] echo
Right Now the Agent Name is Linux
[Pipeline] node
Running on Slave 1 in /home/jenkinsslave/jenkins/workspace/test
[Pipeline] {
[Pipeline] echo
TEST
[Pipeline] }
[Pipeline] // node
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Right Now the Agent Name is Linux
[Pipeline] echo
Linux
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS
Run Code Online (Sandbox Code Playgroud)

这可能会在没有懒惰GString和类型强制的情况下工作,但我没有尝试过.