61

I'm using declarative Jenkins pipelines to run some of my build pipelines and was wondering if it is possible to define multiple agent labels.

I have a number of build agents hooked up to my Jenkins and would like for this specific pipeline to be able to be built by various agents that have different labels (but not by ALL agents).

To be more concrete, let's say I have 2 agents with a label 'small', 4 with label 'medium' and 6 with label 'large'. Now I have a pipeline that is very resource-low and I want it to be executed on only a 'small'- or 'medium'-sized agent, but not on a large one as it may cause larger builds to wait in the queue for an unnecessarily long time.

All the examples I've seen so far only use one single label. I tried something like this:

 agent { label 'small, medium' }

But it failed.

I'm using version 2.5 of the Jenkins Pipeline Plugin.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
FrontSide
  • 1,128
  • 2
  • 10
  • 12

5 Answers5

67

You can see the 'Pipeline-syntax' help within your Jenkins installation and see the sample step "node" reference.

You can use exprA||exprB:

node('small||medium') {
    // some block
}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Arcin B
  • 915
  • 7
  • 12
  • 13
    Oh hey that actually worked. For the declarative pipeline it will look like: agent { label 'small||medium' }. Thanks. – FrontSide Apr 13 '17 at 14:03
  • 14
    Not what the OP asked, but worth to mention that the AND operator (&&) works as well if you need both labels: `node('small && medium')` and you can have spaces between operator and labels (more readable). – firepol Oct 27 '17 at 09:03
  • Oddly enough, the online pipeline syntax docs Google pointed me to do not mention expressions in a label. https://jenkins.io/doc/book/pipeline/syntax/ – Jesse Chisholm May 28 '19 at 23:34
  • 6
    I tried this: `agent { label 'mylabel1||mylabel2||mylabel3' }`. And then received this Jenkins error: `There are no nodes with the label '1mylabel1||mylabel2||mylabel3'` even though these are valid node labels and job succeeds when running on any one of these individually. – user9074332 Aug 29 '19 at 15:29
36

EDIT: I misunderstood the question. This answer is only if you know which specific agent you want to run for each stage.

If you need multiple agents you can declare agent none and then declare the agent at each stage.

https://jenkins.io/doc/book/pipeline/jenkinsfile/#using-multiple-agents

From the docs:

pipeline {
    agent none
    stages {
        stage('Build') {
            agent any
            steps {
                checkout scm
                sh 'make'
                stash includes: '**/target/*.jar', name: 'app' 
            }
        }
        stage('Test on Linux') {
            agent { 
                label 'linux'
            }
            steps {
                unstash 'app' 
                sh 'make check'
            }
            post {
                always {
                    junit '**/target/*.xml'
                }
            }
        }
        stage('Test on Windows') {
            agent {
                label 'windows'
            }
            steps {
                unstash 'app'
                bat 'make check' 
            }
            post {
                always {
                    junit '**/target/*.xml'
                }
            }
        }
    }
}
mcalcote
  • 469
  • 3
  • 6
  • 1
    Hey. Thanks. Unfortunately, that's not what I was looking for, though. If we consider this pipeline you posted here, I would like all stages to be able to be executed on EITHER the linux OR the windows agent. – FrontSide Apr 11 '17 at 17:13
  • Ok, I did misunderstand. From what I have read, I don't see a way to declare a subset of agents for the jenkinsfile. Good Luck – mcalcote Apr 11 '17 at 18:27
  • Ok, no bother. It worked fine before the declarative pipelines. Pull-request time I guess. – FrontSide Apr 11 '17 at 19:18
31

This syntax appears to work for me:

agent { label 'linux && java' }
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
gone.skiing
  • 343
  • 3
  • 2
  • 3
    If the logic works as usual, this would mean that the agent would need to have both labels in order to pick this job up, which is exactly the opposite of what I was looking for. The accepted answer above is what I needed. Thanks, though. – FrontSide Aug 18 '17 at 15:21
  • 3
    I missed the or part... my bad. I will leave this here though in case someone is looking for both labels. – gone.skiing Aug 19 '17 at 16:14
  • 3
    This didn't work for me. For some reason it expected a single label named 'linux&&java'. – João Portela Nov 20 '18 at 10:30
  • 2
    @JoãoPortela same here, it didn't work for me, expecting the same behaviour. – smc Jun 07 '19 at 17:43
12

As described in Jenkins pipeline documentation and by Vadim Kotov one can use operators in label definition.

So in your case if you want to run your jobs on nodes with specific labels, the declarative way goes like this:

agent { label('small || medium') }

And here are some examples from Jenkins page using different operators

// with AND operator
agent { label('windows && jdk9 )')  }
 
// a more complex one
agent { label('postgres && !vm && (linux || freebsd)')  } 

Notes

When constructing those definitions one just needs to consider following rules/restrictions:

  • All operators are left-associative
  • Labels or agent names can be surrounded with quotation marks if they contain characters that would conflict with the operator syntax
  • Expressions can be written without whitespace
  • Jenkins will ignore whitespace when evaluating expressions
  • Matching labels or agent names with wildcards or regular expressions is not supported
  • An empty expression will always evaluate to true, matching all agents
gitrust
  • 199
  • 1
  • 8
0

Create a another label call 'small-or-medium' that has 6 all agents. Then in Jenkinsfile:

agent { label 'small-or-medium' }
Bing Shiao
  • 69
  • 7
  • 1
    I can confirm this works in a certain way. I tested it like so: Two nodes with slightly differently configured fedora systems. Labeled them both "fedora". In the Jenkinsfile: agent { label 'fedora' } When the build starts, it would pick one node at random. But if you started it again, then it would immediately start on the next node as well. – Freitags Jan 31 '18 at 19:01