webentwicklung-frage-antwort-db.com.de

In einer deklarativen Jenkins-Pipeline - kann ich die Agentenbezeichnung dynamisch festlegen?

Gibt es eine Möglichkeit, die Agentenbezeichnung dynamisch und nicht als einfache Zeichenfolge festzulegen?

Der Job hat 2 Stufen:

  1. Erste Phase - Läuft immer auf einem "Master" -Agenten. Am Ende dieser Stufe weiß ich, auf welchen Agenten die 2. Stufe laufen soll.
  2. Zweite Stufe - sollte auf dem in der ersten Stufe festgelegten Agenten laufen.

Mein (nicht funktionierender) Versuch sieht so aus:

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

Das erste Echo funktioniert einwandfrei und "my_node_label" wird gedruckt. Die zweite Stufe läuft nicht auf einem Agenten mit der Bezeichnung "my_node_label" und die Konsole druckt: 

Es gibt keine Knoten mit der Bezeichnung "null"

Vielleicht kann es helfen - wenn ich einfach "$ {env}" in das Label-Feld stelle, kann ich feststellen, dass dies eine Java-Klasse ist, die gedruckt wird:

Es gibt keine Knoten mit der Bezeichnung "[email protected]".

16

Um zu sehen, wie dies funktioniert, verwenden Sie ein GString-Objekt, um eine println auszuführen und gleichzeitig die Variable für den agentName zurückzugeben. Sie können der Ausgabe entnehmen, dass diese Zeile vor jedem anderen Pipeline-Code ausgewertet wird. 

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

    }
}

Konsolenausgabe (Beachten Sie, dass es in dieser Instanz keinen Knoten mit der Bezeichnung Windows gibt. Daher wurde der Vorgang abgebrochen, nachdem er nicht gefunden wurde.) 

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

Beachten Sie, wie die Zeile Right Now the Agent Name is Windows sehr früh in der Ausgabe erscheint. Dies erklärt, warum Ihr Wert null ist. Diese Anweisung wird lange vor dem Ändern der Variablen durch Ihr Skript ausgewertet. 

Ich könnte versuchen, eine faule GString zu verwenden, um die Variable später zu erhalten. 

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

Leider wird ein Fehler ausgegeben, da ein Typ von String erwartet wird. Anscheinend kann er den nicht faulen GString zu einem String alleine zwingen, nicht aber die faule Version. Wenn ich also einem String Zwang erzwinge, wertet er natürlich die Variable zu diesem Zeitpunkt aus (was erneut ist, bevor der Pipeline-Code tatsächlich ausgeführt wird). 

agent { label agentLabel as String }

Sie können das Problem lösen, indem Sie auf die alte Knotenzuweisungsmethode zurückgreifen:

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

Sie können an dieser Konsolenausgabe sehen, dass sie den Linux-Knoten jetzt richtig findet und die Pipeline beendet. Die frühe Auswertung, während agentName == Windows nie vorkommt: 

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

Das würde wahrscheinlich ohne die faule GString und den Typ Zwang funktionieren, aber das habe ich nicht versucht. 

5
Rob Hales

So habe ich es gemacht: Mix Scripted und Declarative Pipeline. Zuerst habe ich die Skriptsyntax verwendet, um beispielsweise den Zweig zu finden, in dem ich bin. Definieren Sie dann die Variable AGENT_LABEL. Diese Variable kann überall in der deklarativen Pipeline verwendet werden 

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

es könnte sich etwas um den Kontext des Skriptblocks handeln.

dies funktioniert, mit der Bezeichnung "Docker" in der zweiten Phase:

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

dies gilt nicht (erhält das gleiche Es gibt keine Knoten mit dem Label "Null" -Fehler):

def hotLabel = null

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

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

Das hat für mich funktioniert:

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
2
Susan

Der Workflow sollte von einem parametrisierten Job stammen, um die Variable dynamisch einzufügen. Ich habe festgestellt, dass die folgende Lösung einfach mit Inline-Stringoperationen funktioniert:

 String Parameter

pipeline {

   agent { label 'LBL && '+nodeLabel }
   ...
}
0
jxramos