如何获取包括主节点在内的所有分配标签的Jenkins节点列表?

28
我正在创建Jenkins管道作业,需要在所有打上特定标签的节点上运行作业。 因此,我试图获取分配有某个标签的节点名称列表。 (使用节点可以使用 getAssignedLabels() 获取标签) jenkins.model.Jenkins.instance.nodes 中的 nodes 列表似乎不包含我需要包含在搜索中的主节点。 我的当前解决方案是迭代 jenkins.model.Jenkins.instance.computers 并使用 getNode() 方法来获取节点。 这种方法有效,但在Jenkins的javadoc中,我看到这个列表可能不是最新的。 从长远来看,我将添加(动态)云节点,并担心那时我将无法使用 computers。 什么是获取所有当前节点列表的正确方法? 以下是我现在正在做的事情:
@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
}
11个回答

18
更新的答案:在流水线中使用 nodesByLabel 命令获取所有被分配到标签的节点。

4
这是更现代的答案。你甚至可以尝试像这样做:nodeList = nodesByLabel label: 'LABEL1||LABEL2&&!ANOTHER', offline: true - Steven the Easily Amused
4
使用它时,你需要安装“Pipeline Utility Steps”。请参考 https://plugins.jenkins.io/pipeline-utility-steps/。 - Maxim Suslov

16

这是我目前的做法。我没有找到其他更好的方法:

@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 包含主节点和所有从节点。


1
@Oliver 把代码从 Jenkins.instance.computers 改成了 Jenkins.get.computers - 他真是知道自己在干什么。 - Patrick B.
卢克,看源代码!https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/model/Jenkins.java#L818 - Oliver
2
你的代码导致了 groovy.lang.MissingPropertyException: No such property: get for class: jenkins.model.Jenkins。请将 jenkins.model.Jenkins.get 改为 jenkins.model.Jenkins.get() - Boris

9

这里是一个更易读且更简洁的功能性解决方案:

def nodes = jenkins.model.Jenkins.get().computers
  .findAll{ it.node.labelString.contains(label) }
  .collect{ it.node.selfLabel.name }

你可以在Jenkins的脚本控制台中进行验证。

8
更新至@patrick-b的答案:如果您有包含相同字符串的标签,则contains可能会出现错误,我已添加了拆分步骤以检查每个用空格分隔的标签。
@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
}

1
上面的代码总是返回一个空列表。实际上,l.equals(label) 需要改为 (l == label)。我还添加了一个 if (c.isOnline()) 检查,以确保只返回在线从机。 - Nick Holt

2

使用 @towel 指出的 nodesByLabel 可能是大多数情况下的解决方案。我发现 nodesByLabel 的一个限制是没有办法无差别地选择所有节点。由于脚本安全性的原因,我也不能使用其他解决方案之一,其中有些可能非常危险,所以我更喜欢不批准它们的使用。

作为替代方案,您可以将函数添加为管道库,从而允许使用这些函数。由于管道库可以设置为完全在管理员控制下,因此选择这条路线更安全。要这样做,请设置管道库(我认为它是否全局并不重要,但对我来说是)。然后将以下内容添加到文件 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)
                }
            }
        }]
    }
}

然后可以如下使用:
pipeline {
    agent none
    stages {
        stage('Parallel on all nodes') {
            steps {
                parallelRunOnNodes { nodeLabel ->
                    println(nodeLabel)
                }
            }
        }
    }
}

显然,根据您的实际情况进行调整,例如可以添加其他参数以过滤数据,也许您不关心并行等。

很棒的解决方案!我试图编辑它,使其只能为包含特定单词标签的节点创建阶段。你能帮忙吗?我尝试添加agent.node.labelString.contains("label-")但是它会出现No such property: Entry for class: java.util.Map错误,我认为这是因为contains返回布尔值而不是Map。 - Pamela Sarkisyan
1
@PamelaSarkisyan 在调用 collectEntries 之前,你需要先过滤节点。可以尝试使用以下代码:jenkins.model.Jenkins.get().computers.findAll { it.node.selfLabel.name.contains("label-) }.collectEntries ... - GManz

1
尝试使用for (aSlave in hudson.model.Hudson.instance.slaves) {}aSlave.getLabelString());来获取所有节点的标签。通过这种方式,您可以构建每个标签的节点列表。

2
“slaves”已被弃用(您应该使用“nodes”),而“nodes”不包含主节点。 - Patrick B.

1
我认为你可以用以下方式完成这个任务:

def nodes = Jenkins.get.getLabel('my-label').getNodes()
for (int i = 0; i < nodes.size(); i++) {
    node(nodes[i].getNodeName()) {
        // on node
    }
}

我不确定这是否适用于云节点。

是的,它可以与云节点一起使用。我们使用类似这样的东西: nodes = Jenkins.instance.getLabel('GO_BUILDER||BASIC_SLAVE').getNodes().collect{it.getNodeName()}在我们的情况下,BASIC_SLAVE是云节点。您甚至可以在主节点上包含标签,但要小心,主节点返回为空字符串! - Steven the Easily Amused

0

获取节点的标签显示名称的另一种方法

def jenkins = Jenkins.instance
def computers = jenkins.computers
computers.each {
   println "${it.displayName} ${it.hostName}"
}

def labels = jenkins.getLabels()
labels.each {
   println "${it.displayName}"
}

1
请在仅包含代码的答案周围添加上下文。 - Stuart.Sklinar

0

我将原问题和https://dev59.com/7lYN5IYBdhLWcg3wxqhu#54145233的答案合并,并将其保存为共享库方法。

vars/nodeNames.groovy

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
}

一旦配置了共享库,请参见https://www.jenkins.io/doc/book/pipeline/shared-libraries/,这可以用作

@Library("my-jenkins-shared-lib") _

print ("linux pipeline can run on" + nodeNames("linux"))

0

这是我的答案

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接