Reputation: 12383
I'm creating a Jenkins pipeline job and I need to run a job on all nodes labelled with a certain label.
Therefore I'm trying to get a list of node names assigned with a certain label. (With a node I can get the labels with getAssignedLabels()
)
The nodes
-list in jenkins.model.Jenkins.instance.nodes
seems not contain the master-node which I need to include in my search.
My current solution is to iterate over the jenkins.model.Jenkins.instance.computers
and use the getNode()
-method to get the node. This works, but in the javadoc of Jenkins I'm reading the this list might not be up-to-date.
In the long-run I will add (dynamically) cloud-nodes and I'm afraid that I won't be able to use computers
then.
What is the right way to get the list of all current nodes?
This is what I'm doing right now:
@NonCPS
def nodeNames(label) {
def nodes = []
jenkins.model.Jenkins.instance.computers.each { c ->
if (c.node.labelString.contains(label)) {
nodes.add(c.node.selfLabel.name)
}
}
return nodes
}
Upvotes: 29
Views: 64729
Reputation: 1295
I combined the answers from the original question and https://stackoverflow.com/a/54145233/1817610 and saved it as a shared library method
def call(String label) {
def nodes = []
jenkins.model.Jenkins.instance.computers.each { c ->
c.node.labelString.split(/\s+/).each { l ->
if (l != null && l.equals(label)) {
nodes.add(c.node.selfLabel.name)
}
}
}
return nodes
}
Once the shared library is configured, see https://www.jenkins.io/doc/book/pipeline/shared-libraries/, this can be used as
@Library("my-jenkins-shared-lib") _
print ("linux pipeline can run on" + nodeNames("linux"))
Upvotes: 0
Reputation: 2851
Another wat to get Labels
and Display Name
of nodes
def jenkins = Jenkins.instance
def computers = jenkins.computers
computers.each {
println "${it.displayName} ${it.hostName}"
}
def labels = jenkins.getLabels()
labels.each {
println "${it.displayName}"
}
Upvotes: 0
Reputation: 12383
This is the way I'm doing it right now. I haven't found anything else:
@NonCPS
def hostNames(label) {
def nodes = []
jenkins.model.Jenkins.get().computers.each { c ->
if (c.node.labelString.contains(label)) {
nodes.add(c.node.selfLabel.name)
}
}
return nodes
}
jenkins.model.Jenkins.get.computers
contains the master-node and all the slaves.
Upvotes: 18
Reputation: 13841
This is one of the top Google hits for how to list nodes on a Jenkins server. If you're just looking for the list of nodes, it can be viewed at the following server URL:
http://JENKINS_HOSTNAME:JENKINS_PORT/computer/
The result is a table displaying the name, OS, JVM version, clock sync status, remoting version and response time of known nodes. It also displays whether the node image (well, JAR) is significantly outdated or subject to error/security alerts.
If there is no access available to API calls, the URL can always be scraped and parsed to get the list of nodes and any of the other data included in the table.
Upvotes: -2
Reputation: 1669
using nodesByLabel
as pointed out by @towel is probably the solution in most cases. One limitation I found with nodesByLabel
is that there is no way to indiscriminately select all nodes. I can't use any of the other solutions either because of script security, some of these can be pretty dangerous, so I preferred not to approve them for usage.
As an alternatively, you can add a function as a pipeline library, which will allow usage of these functions. Since pipeline libraries can be set up so they are fully under the administrator's control, it's safer to go with this route. To do so, set up a pipeline library (I don't think it matters if it's global or not, but for me it is). Then add the following contents to the file vars/parallelRunOnNodes.groovy
:
def call(Closure callback) {
parallel jenkins.model.Jenkins.get().computers.collectEntries { agent ->
def nodeLabel = agent.node.selfLabel.name
["${nodeLabel}": {
node("${nodeLabel}") {
stage("${nodeLabel}") {
callback(nodeLabel)
}
}
}]
}
}
Which can then be used as follows:
pipeline {
agent none
stages {
stage('Parallel on all nodes') {
steps {
parallelRunOnNodes { nodeLabel ->
println(nodeLabel)
}
}
}
}
}
Obviously adjust as you see fit, e.g. you can add additional parameters to filter, maybe you don't care about parallel etc.
Upvotes: 2
Reputation: 444
Here is my answer
String labelIWantServersOf = "XXXX"; // This is the label assosiated with nodes for which i want the server names of
List serverList = [];
for (aSlave in hudson.model.Hudson.instance.slaves) {
if (aSlave.getLabelString().indexOf(labelIWantServersOf ) > -1) {
if(!aSlave.getComputer().isOffline() ){
serverList.add(aSlave.name);
}
}
}
return serverList;
Upvotes: 0
Reputation: 24453
Here is a functional solution which is more readable and concise:
def nodes = jenkins.model.Jenkins.get().computers
.findAll{ it.node.labelString.contains(label) }
.collect{ it.node.selfLabel.name }
You can verify it in the Jenkins Script Console.
Upvotes: 9
Reputation: 1699
I think that you can do this with:
def nodes = Jenkins.get.getLabel('my-label').getNodes()
for (int i = 0; i < nodes.size(); i++) {
node(nodes[i].getNodeName()) {
// on node
}
}
I don't know for sure whether this works with cloud nodes.
Upvotes: 2
Reputation: 334
Update to @patrick-b answer : contains can be buggy if you have labels containing same string, I've added a split step do check every label separated with spaces.
@NonCPS
def hostNames(label) {
def nodes = []
jenkins.model.Jenkins.get.computers.each { c ->
c.node.labelString.split(/\s+/).each { l ->
if (l != null && l.equals(label)) {
nodes.add(c.node.selfLabel.name)
}
}
}
return nodes
}
Upvotes: 8
Reputation: 2214
Updated answer: in a pipeline use nodesByLabel
to get all nodes assigned to a label.
Upvotes: 20
Reputation: 623
Try using
for (aSlave in hudson.model.Hudson.instance.slaves) {}
and aSlave.getLabelString());
to get all the labels for all of your nodes. You can construct a list of nodes per label this way.
Upvotes: 1