web-dev-qa-db-fra.com

Dans un pipeline jenkins déclaratif, puis-je définir le libellé de l'agent de manière dynamique?

Existe-t-il un moyen de définir le libellé de l'agent de manière dynamique et non comme une chaîne?

Le travail comporte 2 étapes:

  1. Première étape - Fonctionne toujours sur un agent "maître". À la fin de cette étape, je saurai sur quel agent la deuxième étape doit être exécutée.
  2. Deuxième étape - devrait être confié à l’agent choisi lors de la première étape.

Ma tentative (qui ne fonctionne pas) ressemble à ceci:

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

Le premier écho fonctionne correctement et "my_node_label" est imprimé . La deuxième étape ne peut pas s'exécuter sur un agent nommé "my_node_label" et la console affiche: 

Il n’existe pas de nœuds portant l’étiquette ‘null’

Peut-être que cela peut aider - si je viens de mettre "$ {env}" dans le champ de l'étiquette, je peux voir qu'il s'agit d'une classe Java telle qu'elle est imprimée:

Il n’existe pas de nœuds portant l’étiquette «org.jenkinsci.plugins.workflow.cps.EnvActionImpl@79c0ce06».

16
Gilad Shahrabani

Pour voir comment cela fonctionne, utilisez un objet GString pour créer une println et renvoyer la variable correspondant au nom de l'agent en même temps. Vous voyez sur la sortie que cette ligne est évaluée bien avant tout autre code de pipeline. 

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

    }
}

Sortie de la console (notez que je n'ai pas de noeud sur cette instance nommée Windows, alors j'ai abandonné après l'avoir trouvée): 

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

Notez que la ligne Right Now the Agent Name is Windows apparaît très tôt dans la sortie. Cela explique pourquoi votre valeur est nulle. Cette instruction est évaluée bien avant que votre script modifie la variable. 

Je pourrais essayer d'utiliser une variable GString paresseuse pour obtenir la variable plus tard. 

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

Malheureusement, cela génère une erreur car il attend un type de chaîne. Apparemment, il peut contraindre le GString non paresseux à une chaîne tout seul, mais pas à la version paresseuse. Ainsi, lorsque je force la contrainte sur une chaîne, bien sûr, il évalue la variable à ce moment-là (c'est-à-dire avant que le code de pipeline ne soit réellement exécuté). 

agent { label agentLabel as String }

Vous pouvez résoudre le problème en retenant l'ancienne méthode d'allocation de nœud:

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

Vous pouvez voir à partir de cette sortie de console qu'elle trouve maintenant correctement le nœud Linux et termine le pipeline. La première évaluation alors que agentName == Windows ne se produit jamais: 

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

Cela fonctionnerait probablement sans la variable paresseuse GString et le type de contrainte plus tard, mais je n'ai pas essayé cela. 

5
Rob Hales

Voici comment je l'ai fait: mélange de pipeline scripté et déclaratif. J'ai d'abord utilisé la syntaxe scriptée pour trouver, par exemple, la branche sur laquelle je suis. Définissez ensuite la variable AGENT_LABEL. Cette variable peut être utilisée n'importe où sur le pipeline déclaratif 

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

cela pourrait être quelque chose à propos du contexte du bloc de script.

cela fonctionne, en utilisant une étiquette de 'docker' dans la deuxième étape:

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

cela n’est pas le cas (il en va de même. Il n’existe pas de nœuds portant l’erreur «null»)

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

Cela a fonctionné pour moi:

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

Je souhaitais que le workflow dérive d'un travail paramétré pour injecter dynamiquement la variable. J'ai trouvé que la solution suivante fonctionnait bien en utilisant simplement des opérations de chaîne en ligne:

 String Parameter

pipeline {

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