Jenkins共享库调用Kubernetes插件DSL报No Such DSL Method问题求助
问题背景
我们通过JCasC配置了如下Jenkins全局共享库:
controller: JCasC: configScripts: jenkins-casc-unclassified: | unclassified: globalLibraries: libraries: - defaultVersion: "master" implicit: true name: "com.company.jenkins" retriever: modernSCM: scm: github: configuredByUrl: true credentialsId: "..." id: "..." repoOwner: "Company" repository: "Company_CICD" repositoryUrl: "https://github.com/company/Company_CICD.git" traits: - gitHubBranchDiscovery: strategyId: 1 - gitHubPullRequestDiscovery: strategyId: 1 - gitHubForkDiscovery: strategyId: 1 trust: "gitHubTrustPermissions"
我们为Kubernetes插件封装了便捷函数以大幅精简代码,尝试再精简2行代码时遇到了如下报错:
java.lang.NoSuchMethodError: No such DSL method 'getPodTemplate'
我们未修改导入语句和函数名,却触发了该报错。
可正常运行的写法
Util.groovy 实现
// src/com/company/jenkins/Util.groovy package com.onscale.jenkins def getPodTemplate(String label, List<String> containers, List<String> volumes, String yaml) { containers = containers.collect { value -> return getContainerTemplate(value) } volumes = volumes.collect { value -> return getVolume(value) } return [ label: label, yaml: yaml, containers: containers, volumes: volumes ] }
Jenkinsfile 调用
// Jenkinsfile def util = new com.onscale.jenkins.Util() podTemplate ( util.getPodTemplate( 'jenkinsbuild', // Label ['jnlp', 'docker', 'kubectl'], // Containers ['host-path'], // Volumes podSpec ) )
无法运行的写法
Util.groovy 实现
// src/com/company/jenkins/Util.groovy package com.onscale.jenkins def getPodTemplate(String label, List<String> containers, List<String> volumes, String yaml) { containers = containers.collect { value -> return getContainerTemplate(value) } volumes = volumes.collect { value -> return getVolume(value) } return podTemplate( label: label, yaml: yaml, containers: containers, volumes: volumes ) }
Jenkinsfile 调用
// Jenkinsfile def util = new com.onscale.jenkins.Util() util.getPodTemplate( 'jenkinsbuild', // Label ['jnlp', 'docker', 'kubectl'], // Containers ['host-path'], // Volumes podSpec )
两种写法的唯一差异是getPodTemplate方法是否直接调用并返回podTemplate的执行结果。已检索相关资料,同类常见问题不匹配当前场景:我们没有使用var/function.groovy的共享库实现方式,而是通过new关键字实例化全局库中src目录下的类来调用方法。
问题原因
Jenkins Pipeline 提供的所有DSL方法(包括Kubernetes插件提供的podTemplate)默认仅绑定在Jenkinsfile的运行上下文(即Jenkinsfile脚本本身对应的Script实例)中。
src目录下的普通Groovy类是独立的类对象,实例化后不会自动继承Jenkins的DSL上下文。第一种写法中podTemplate是在Jenkinsfile的上下文中调用,因此可以正常识别;第二种写法中podTemplate是在Util类的方法作用域内调用,Util类的作用域中不存在该DSL方法,因此抛出找不到方法的错误。
解决方案
最通用的解决方式是将Jenkins运行上下文传入Util类,通过上下文调用DSL方法,修改后的代码如下:
修改后的Util.groovy
// src/com/onscale/jenkins/Util.groovy package com.onscale.jenkins class Util { // 存储传入的Jenkins上下文 private final Script jenkinsContext // 构造函数接收Jenkins上下文 Util(Script jenkinsContext) { this.jenkinsContext = jenkinsContext } def getPodTemplate(String label, List<String> containers, List<String> volumes, String yaml) { containers = containers.collect { value -> // 如果getContainerTemplate也是DSL方法,同样通过上下文调用 return jenkinsContext.getContainerTemplate(value) } volumes = volumes.collect { value -> // 如果getVolume也是DSL方法,同样通过上下文调用 return jenkinsContext.getVolume(value) } // 通过上下文调用podTemplate DSL方法 return jenkinsContext.podTemplate( label: label, yaml: yaml, containers: containers, volumes: volumes ) } }
修改后的Jenkinsfile调用
// Jenkinsfile // 实例化时传入当前Jenkinsfile的上下文(this) def util = new com.onscale.jenkins.Util(this) util.getPodTemplate( 'jenkinsbuild', ['jnlp', 'docker', 'kubectl'], ['host-path'], podSpec )
如果不想修改Util类的构造函数,也可以将上下文作为getPodTemplate方法的入参传入,实现逻辑完全一致。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

