40

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

这项工作有2个阶段:

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

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

没有标签为“null”的节点</p>

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

没有标签为“org.jenkinsci.plugins.workflow.cps.EnvActionImpl@79c0ce06”的节点</p>

4

6 回答 6

35

这是我的做法:混合脚本化和声明性管道。首先,我使用脚本语法来查找例如我所在的分支。然后定义 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"
            }
        }
    }
}
于 2018-03-06T14:04:10.010 回答
21

要查看其工作原理,请使用GString对象执行 aprintln并同时返回 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
                }
            }
    }

    }
}

控制台输出(请注意,我在此实例上实际上没有标记为 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

请注意该行是如何Right Now the Agent Name is Windows在输出的早期出现的。这解释了为什么您的值为 null。该语句在您的脚本修改变量之前很久就被评估。

稍后我可能会尝试使用惰性GString来获取变量。

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

不幸的是,这会引发错误,因为它需要一种 String。显然,它可以将非惰性 GString 强制转换为 String ,但不能强制惰性版本。因此,当我强制强制转换为 String 时,它当然会在那个时候评估变量(这也是在管道代码实际运行之前)。

agent { label agentLabel as String }

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

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

您可以从此控制台输出中看到,它现在正确地找到了 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

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

于 2017-10-11T21:00:23.730 回答
4

它可能与脚本块的上下文有关。

这有效,在第二阶段使用“docker”标签:

def hotLabel = 'docker'

pipeline {
    agent { label 'master' }
    stages {
        stage('Stage1') {
            steps {
                echo "node_name: ${hotLabel}"
            }
        }

        stage('Stage2') {
            agent { label "${hotLabel}" }
            steps {
                echo "node_name: ${hotLabel}"
            }
        }
    }
}

这没有(得到相同的没有标签为“空”错误的节点):

def hotLabel = null

pipeline {
    agent { label 'master' }
    stages {
        stage('Stage1') {
            steps {
                script {
                    hotLabel = "docker"
                }
            }
        }

        stage('Stage2') {
            agent { label "${hotLabel}" }
            steps {
                echo "node_name: ${hotLabel}"
            }
        }
    }
}
于 2017-10-08T12:57:49.433 回答
3

我使用三元运算符让我的动态变化。

对于下文,如果 Jenkins 管道名称以“prod”结尾,则使用的标签为“myagent-prd”。否则,它只是“myagent”。

def ENVIRONMENT_NAME="${JOB_NAME}".tokenize('-').last().toLowerCase()

pipeline {
    agent {
      label "myagent${ENVIRONMENT_NAME == "prod" ? "-prd" : "" }"
    }
于 2020-08-12T08:06:48.540 回答
2

这对我有用:

env.agentName = ""

branch_name = "10.1.0"
pipeline {
    agent none

    stages {
        stage('Prep') {
            steps {
                script {
                    println branch_name
                    if ("${branch_name}" == "9.2.0") {
                        env.agentName = "9.2agent"
                    } else {
                        env.agentName = "10.1agent"
                    }
                }
            }
        }

        stage('Finish') {
            steps {
                node (agentName as String) { println env.agentName }
                script {
                    println agentName
                }
            }
        }

    }
}

Output:
SuccessConsole Output
Started by user build
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] stage
[Pipeline] { (Prep)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
10.1.0
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Finish)
[Pipeline] node
Running on 10.1agent in /home/build/jenkins/workspace/testlabel
[Pipeline] {
[Pipeline] echo
rbreg6
[Pipeline] }
[Pipeline] // node
[Pipeline] script
[Pipeline] {
[Pipeline] echo
rbreg6
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS

Changing the branch name to 9.2.0:
Started by user build
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] stage
[Pipeline] { (Prep)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
9.2.0
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Finish)
[Pipeline] node
Running on 9.2agent in /shared/build/workspace/testlabel
[Pipeline] {
[Pipeline] echo
rbregistry
[Pipeline] }
[Pipeline] // node
[Pipeline] script
[Pipeline] {
[Pipeline] echo
rbregistry
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS
于 2018-06-28T19:37:59.563 回答
2

我希望工作流源于参数化作业以动态注入变量。我发现以下解决方案只需使用内联字符串操作就可以很好地工作:

字符串参数

pipeline {

   agent { label 'LBL && '+nodeLabel }
   ...
}
于 2018-09-26T05:46:59.043 回答