Jenkins: 使用groovy + job-dsl 创建并触发job

背景:

我们的 Automation 测试脚本需要在10个不同语言的机器上跑,本地化测试产品。

我们用Jenkins启动测试执行,需要同时向1-10个机器发送文件和脚本运行命令,现有Jenkins的配置采用master/slave 机制如下:

Dispatcher Job:

1。 启用参数化,每个语言机器传递两个参数:

- Choice Parameter: slave Node 名,比如这里的NodeLabel1,表示第一台目标机器

- File Parameter: 要发送给目标机器的文件

2。 在Build Steps中trigger seed job:

Seed Job: 设置具体的运行脚本。

现有设计的问题:

运行很流畅,但是维护不方便

  • 每个Slave Node都添加一个Choice Paramter 和 File Parameter,
  • Build Step中也要添加10次trigger seed job,
  • Steps中如有一处脚本改动,需重复改动10次
  • 如果有新添加测试机器,需要在Parameters中手动添加新Node, 在Steps中也要添加。

改进需求:

自动获取所有Node列表,减少不必要的手动增添Node。

在Build Steps中,通过脚本trigger seed job,这样避免重复设置10次trigger step, 提高可重复性(Reusability)。

改进方案:

使用Groovy脚本,安装Jenkins插件:

  • Active Choices: 一个蛮好的参数化插件,可插入Groovy脚本和文件(集成Scriptlet插件)。

  • Scriptler:Groovy脚本插件,可以集中管理脚本文件。

  • Job-DSL: 一个很好的利用DSL设置和运行Job的插件。

具体实施:

准备global scripts,获取全部节点,用的是scriptler插件。

1。 在Jenkins->Scriptler中创建getAllNodeByProject.groovy文件,用来获取所有的Node机器。需要的话也可以加入一些筛选条件,比如在线与否。

scriptler中支持参数传递,这里的project就是预先设置的参数,可在job调用该脚本时进行设置。


def list = jenkins.model.Jenkins.instance.slaves.findAll{
if (it.name.contains(project)) it.name
}.collect{it.name}
list.add(0,"None")
return list

2。 在Jenkins->Scriptler中创建getRuntimeNodes.groovy文件,用来获取dispatcher job在运行时指定的Node机器。


import hudson.model.*
def list =""
def runable=false
def build = Thread.currentThread()?.executable
// get the selected node parameter value at runtime
def nodes = build?.actions.find { it instanceof ParametersAction }?.parameters.collect{
(it instanceof StringParameterValue)?it.value:""
} as List
println "node is $nodes"
nodes.unique().removeAll(["None"])
nodes.remove(" ")
nodes.remove("")
if (nodes!=[]) {
list=nodes.join(",").toString()
}
println "list is: $list"
if (list!=" " && list!="") runable=true
println "runable is $runable"
build.addAction( new ParametersAction([new StringParameterValue("runtimeNodes",list)]))
build.addAction( new ParametersAction([new BooleanParameterValue("runable",runable)]))

运行结果是,在dispatcher job runtime会新建两个参数:

  • String参数 runtimeNodes: 存放运行时获取用户指定的Node 机器列表,用于后续在这些node 机器上分别trigger seed job

  • 布尔型参数 runable:如果没有指定任何Node,则将runable设为false, 即不会trigger seed job

创建main,dispatcher和seed jobs

手动创建一个名为main的 job, 用来动态生成dispatcher and seed jobs.

在main中用job-dsl创建dispatcher job

在main job中,插入一个Process Job DSLs 构建步骤, 下面的代码会在运行时创建一个名为dispatcher的job:

  • 为每个language node (“Client_CHS","Client_JPN") 设置了active choice node 参数和File参数。
  • 创建一个conditional step, 如果符合条件,则trigger seed job,并将用户运行时指定的所有node以NodeListFactory参数方式传给seed job。

import hudson.model.* // get all available nodes if its name contains "client" - specific for our project use;
def nodes = hudson.model.Hudson.instance.slaves.findAll{
if (it.name.contains("Client")) it.name
}.collect{it.name}
nodes.add(0,"None") //def nodes = ["Client_JPN","Client_CHS"] defineJob(nodes-["None"],"dispatcher") // setup the dispatcher job // method to define a dispatcher job
def defineJob(nodes,jobName) {
return job(jobName) {
def list =[]
nodes.each {
def node =it
parameters {
activeChoiceParam(node) {
description('Allows user choose from choices')
filterable()
choiceType('SINGLE_SELECT')
scriptlerScript('getAllNodesByProject.groovy') {
parameter('project', 'Client')
}
}
fileParam(node+'_File', 'Select test case file to upload')
}
} steps {
//systemGroovyScriptFile('${JENKINS_HOME}\\scriptler\\scripts\\getRuntimeNodes.groovy') {
systemGroovyCommand(readFileFromWorkspace("${JENKINS_HOME}\\scriptler\\scripts\\getRuntimeNodes.groovy")){
}
conditionalSteps {
condition {
booleanCondition("\${runable}")
} steps{ downstreamParameterized {
trigger('seed') {
/* parameters{
println node
nodeLabelBuildParameter {
name(node)
nodeLabel(node)
}*/
parameterFactories {
nodeListBuildParameterFactory { // The name of the parameter to set.
name("test")
// A comma separated list of nodes to execute the job on.
nodeListString("\${runtimeNodes}") }
//booleanParam("f",true) /
}
}
}
}
}
}
}
}

现在运行 main job,成功后你会看到 dispatcher job 和 seed job 生成了

进入 dispatcher job, 选择 build with parameters,会看到我们想要的参数都列出来了。

在main中用job-dsl创建 seed job

打开main job,再次插入一个Process Job DSLs 构建步骤, 下面的代码会在运行时创建一个名为 seed 的job, seed job 会 触发实际执行的自动化脚本,这里为简单起见,我们让它执行一行命令。这里用到了Node and Label parameter 插件


job("seed") {
concurrentBuild()
/*parameters{
nodeParam("node") {
description('Select Test Node')
defaultNodes(["Test Node"])
allowedNodes(["Test Node"])
}*/ steps {
batchFile('echo Hello World!')
}
}

现在再运行一次main job, 回到job 列表中,可以看到dispatcher和seed都列在其中了。

点击进入seed job, 便可以看到上面定义的batch command step了。

现在,dispatcher和seed job都就位了,接下来我们需要修改dispatcher,让它运行时trigger seed job.

测试:允许dispatcher job

运行的时候我们手动或自动触发 dispatcher job.

进入dispatcher job, 选择 build with parameters,

  • 将所有Node 都设为"None", 运行结果显示,seed job 没有trigger。成功

  • 指定一个或多个Node(不为None),运行结果显示,seed job在指定Nodes上触发了。成功

上述操作还没有将File Parameter的使用加上去,后续再补充。欢迎一起讨论!

Jenkins: 使用groovy + job-dsl 创建并触发job的更多相关文章

  1. 第一篇:groovy对DSL的语法支持

    引子 我们用一段gradle的脚本做引子,理解这一段脚本与一般的groovy代码是怎么联系起来的 buildscript { repositories { jcenter() mavenLocal() ...

  2. Groovy 与 DSL

    一:DSL 概念 指的是用于一个特定领域的语言(功能领域.业务领域).在这个给出的概念中有 3个重点: 只用于一个特定领域,而非所有通用领域,比如 Java / C++就是用于通用领域,而不可被称为 ...

  3. Jenkins pipeline job 根据参数动态获取触发事件的分支

    此文需要有Jenkins pipeline job 的简单使用经验 场景 我们日常的测试函数, 一般是不能仅仅在本地跑的,还需要一个公共的跑测试的环境,作为合并新的PR的依据. 如果用Jenkins ...

  4. jenkins构建触发器详解-不登录触发远程构建详解

    利用jenkins的远程构建功能,我们可以使用任何脚本,甚至定制一个Web页来控制Job的执行,但是远程构建你如果直接使用的话,老是需要登录才能执行,如何避免登录?稍微折腾了一下,调通了. 1.首先去 ...

  5. jenkins构建触发器详解-不登录触发远程构建

    利用jenkins的远程构建功能,我们可以使用任何脚本,甚至定制一个Web页来控制Job的执行,但是远程构建你如果直接使用的话,老是需要登录才能执行,如何避免登录?稍微折腾了一下,调通了. 1.首先去 ...

  6. Jenkins进阶-发布后自动创建git tag(5)

    为了便于项目中对发布的版本进行回滚,所以我们每次发布完成以后自动创建git tag. 1,创建一个Jenkins任务,命名成为push_tag_demo: 2,配置<源码管理>,这里配置比 ...

  7. 为什么S/4HANA的销售订单创建会触发生产订单的创建

    调用S/4HANA销售订单创建函数SD_SALES_DOCU_MAINTAIN创建一个销售订单时,会触发生产订单的创建. 销售订单的每个行项目对应一个独立的生产订单,SD_SALES_DOCU_MAI ...

  8. Xcode 自定义控件创建及触发事件

    #pragma mark 控制器的view加载完毕的时候调用 //一般在这里进行界面的初始化 - (void)viewDidLoad { [super viewDidLoad]; NSLog(@&qu ...

  9. jenkins实现master变化时,才触发构建(过滤分支)

    现状:现在是这样的,每个开发push时,都触发jenkins进行构建 期望:只有当代码被push到master时才进行构建 (根据使用的git平台)做这些配置需要先了解一些概念: (github) p ...

随机推荐

  1. 【曝】苹果应用商店逾千款iOS应用存安全漏洞

    据国外网站Ibtimes报道,知名网络安全公司FireEye日前警告称,由于一款名为“JSPatch”.可帮助开发者修改应用程序的软件上存在安全漏洞,导致苹果应用商店内1000多款使用了该框架的iOS ...

  2. Asp.Net 常用工具类之Office—Excel导入(5)

    之前在做一个项目的时候,客户方面只提供了一份简单的Excel文件,且要跟现有数据进行对接. 当时想到的是如果数据量不大,可以Excel一条一条加进去,无奈数据有几十兆!!! 换了一种思维,进行了导入: ...

  3. 算法模板——sap网络最大流 3(递归+邻接矩阵)

    实现功能:同之前 可以看见的是这次的程序优美了许多,代码简短了一倍还多,可是速度却是和原来的邻接表一个级别的(在Codevs上面草地排水那题的运行时间比较,但是显然数据很大时应该比那个慢些),原理差不 ...

  4. 1821: [JSOI2010]Group 部落划分 Group

    1821: [JSOI2010]Group 部落划分 Group Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1308  Solved: 627[Su ...

  5. 简单的add函数的N种写法

    最近在学习es6,看到for-of这里,就想自己写着练习一下,于是就准备写一个小函数add来求和.函数很简单,如add(1,2,3)这样.于是我开始着手 一开始我是这么写的 function add( ...

  6. Python中类的方法属性与方法属性的动态绑定

    最近在学习python,纯粹是自己的兴趣爱好,然而并没有系统地看python编程书籍,觉得上面描述过于繁琐,在网站找了一些学习的网站,发现廖雪峰老师的网站上面的学习资源很不错,而且言简意赅,提取了一些 ...

  7. ng-class 用法

    很长时间不写页面很多angualrjs的指令用法忘了,搜搜网上的千篇一律“不全”: 下面我把ngclass的用法列出来!(注:网上只有2种,我补充一种三维运算) 1:   ng-class=" ...

  8. 混合拉普拉斯分布(LMM)推导及实现

    作者:桂. 时间:2017-03-21  07:25:17 链接:http://www.cnblogs.com/xingshansi/p/6592599.html 声明:欢迎被转载,不过记得注明出处哦 ...

  9. iOS开发之如何修改导航栏的内容

    导航栏的内容由栈顶控制器的navigationItem属性决定. UINavigationItem有以下属性影响着导航栏的内容(通常在子控制器中viewDidLoad方法中调用这些方法): 左上角的返 ...

  10. 使用Atom打造无懈可击的Markdown编辑器

    一直以来都奢想拥有一款全能好用的Markdown编辑器,直到遇到了Atom.废话不多说,直接开搞! 1. 安装Atom 下载安装Atom:https://atom.io/ 2. 增强预览(markdo ...