如何在Jenkins中通过Groovy从WorkflowRun获取hudson.model.Node
问题描述
我在Jenkins流水线构建中用Groovy脚本获取当前运行节点信息,目前的实现是通过Jenkins.instance.getNode(env.NODE_NAME)获取节点:
def currentNode = Jenkins.instance.getNode(env.NODE_NAME) if ( currentNode instanceof org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave ) { println currentNode?.toComputer()?.getContainers()?.collect{ it.image }?.join(', ') ?: '' }
但我认为既然构建在当前节点运行,应该可以直接从currentBuild或currentBuild.rawBuild拿到hudson.model.Node类型的节点实例。尝试用currentBuild.rawBuild.getExecutor().getOwner()时,得到的却是hudson.model.Hudson$MasterComputer类,而实际构建运行在Kubernetes Pod中,我需要的是org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave类型:
currentBuild.rawBuild // 类型:org.jenkinsci.plugins.workflow.job.WorkflowRun .getExecutor() // 类型:hudson.model.OneOffExecutor .getOwner() // 类型:hudson.model.Hudson$MasterComputer
我需要替代方案的核心原因是env.NODE_NAME并非通用:比如通过以下脚本获取历史构建的WorkflowRun时,根本没有env.NODE_NAME可用:
Jenkins.instance .getItemByFullName( JOB_NAME ) .getBuildByNumber( BUILD_NUMBER )
更新信息
我打印了当前workflowRun.actions的类型列表:
println currentBuild.rawBuild .actions .collect { it.getClass() } .join('\n') // 输出结果: class hudson.model.CauseAction class hudson.plugins.jobConfigHistory.JobConfigBadgeAction class jenkins.metrics.impl.TimeInQueueAction class org.jenkinsci.plugins.buildtriggerbadge.BuildTriggerBadgeAction class org.jenkinsci.plugins.workflow.libs.LibrariesAction class com.cloudbees.plugins.credentials.builds.CredentialsParameterBinder class hudson.plugins.git.util.BuildData class io.jenkins.plugins.forensics.git.reference.GitCommitsRecord class hudson.plugins.ansicolor.action.ColorizedAction class hudson.plugins.ansicolor.action.ColorizedAction class org.jenkinsci.plugins.workflow.cps.EnvActionImpl
解决方案建议
1. 从EnvActionImpl中提取节点名称
从你提供的actions列表中可以看到org.jenkinsci.plugins.workflow.cps.EnvActionImpl,这个对象存储了构建的完整环境变量,包括NODE_NAME。可以通过它提取节点名称后,再查询对应的Kubernetes节点:
def workflowRun = currentBuild.rawBuild // 或通过Jenkins.instance获取的历史WorkflowRun def envAction = workflowRun.actions.find { it instanceof org.jenkinsci.plugins.workflow.cps.EnvActionImpl } def nodeName = envAction?.getEnvironment()?.get('NODE_NAME') if (nodeName) { def currentNode = Jenkins.instance.getNode(nodeName) if (currentNode instanceof org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave) { println currentNode?.toComputer()?.getContainers()?.collect{ it.image }?.join(', ') ?: '' } }
2. 直接获取KubernetesPodAction(推荐)
对于Kubernetes插件创建的构建节点,构建实例会关联org.csanchez.jenkins.plugins.kubernetes.actions.KubernetesPodAction(需确保插件版本支持),可以直接从actions中查找该对象,跳过节点名称查询步骤,直接获取Pod和容器信息:
def workflowRun = currentBuild.rawBuild def k8sPodAction = workflowRun.actions.find { it.getClass().name == 'org.csanchez.jenkins.plugins.kubernetes.actions.KubernetesPodAction' } if (k8sPodAction) { def pod = k8sPodAction.getPod() println "Pod名称: ${pod.name}" println "容器镜像: ${pod.containers.collect { it.image }.join(', ')}" // 若需要Node对象,可通过pod.getNodeName()再查询 def k8sNode = Jenkins.instance.getNode(pod.getNodeName()) if (k8sNode instanceof org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave) { // 执行节点相关逻辑 } }
3. 流水线运行时获取当前节点(仅适用于实时执行场景)
如果是在流水线运行过程中获取当前节点,而非查询历史构建,可以通过CpsThreadGroup直接拿到当前执行上下文的节点实例:
import org.jenkinsci.plugins.workflow.cps.CpsThreadGroup import org.jenkinsci.plugins.workflow.cps.CpsThread def currentThread = CpsThreadGroup.current().getThread(0) def nodeContext = currentThread.getExecution().getCurrentHeads()[0].getContext().get(hudson.model.Node.class) if (nodeContext instanceof org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave) { println nodeContext?.toComputer()?.getContainers()?.collect{ it.image }?.join(', ') ?: '' }
注意:上述所有方法都需要确保Jenkins脚本安全策略允许访问对应的类和方法,可能需要在「脚本审批」页面授权相关操作。
内容的提问来源于stack exchange,提问作者Marslo

