标签:全局 通过 导致 contain shang 默认 构建 groovy row
本文分享的小
Tips
是在我前面的文章DevOps建设之基于钉钉OA审批流的自动化上线中提到的,当通过API
自动触发Jenkins Pipeline
流水线执行时,如果原来的流水线中定义了在构建正式开始后还需要接收用户input
的步骤,想要自动绕过或自动执行input
的方法
首先回过头再来看看pipeline input
的语法及功能,参考我之前总结的pipeline input语法
input
指令stage
允许使用input step
提示输入。在stage
将暂停任何后options
已被应用,并在进入前agent
块为stage
或评估when
的条件stage
。如果input
批准,stage
则将继续。作为input
提交的一部分提供的任何参数将在其余的环境中可用stage
。
可选项
input
input
,默认为stage
名称input
表单上“确定”按钮的可选文本input
。默认为允许任何用户。submitter
名称设置(如果存在)基于上面的语法描述,我这里线上发布流水线中input
的功能仅仅是需要用户进行确认,所以没有传递任何参数,通过这种简单的input
控制及timeout
超时机制,实现了用户选择参数并点击开始构建后需要在60秒内二次确认的功能,流水线的部分内容如下
stage(‘Deploy to prod‘){
when {
environment name: ‘PerformType‘, value: ‘Deploy‘
}
steps{
timeout(time:60, unit:‘SECONDS‘) {
input "确认要部署到线上环境吗?"
script{
try {
...
}
catch (exc) {
...
throw(exc)
}
}
}
}
}
到这里问题就产生了,input
的过程是在流水线运行过程中动态出现的,如果是想要在钉钉OA
审批通过后自动通过调用jenkins api
并传入参数让整个流水线自动执行,并且自动进行input
的确认操作或者绕过input
,应该怎么做呢?
刚开始没有任何思路,唯一想到的办法就是把input
的过程从pipeline
中去除掉,这样就没有任何烦恼了
但是为了保留原有pipeline
设计的完整性,显然这种做法不够友好,只是避开了这个难点,是不可取的
通过查找发现这方面的资料很少,最终有用的资料如下
input
语法中可选字段包含id
,每个input
步骤都有一个唯一的ID
。在生成的URL
中可以使用它来继续或中止
例如,可以使用特定的ID
来机械地响应来自某些外部过程/工具的输入
这篇文章中讲到了如何通过Jenkins REST API
恢复暂停的管道?作为参考起到了一定帮助
为了完成整个自动化input
的过程,具体的演进流程如下
Crumb
指的是Jenkins
的CSRF token
,Jenkins
服务器为了阻止不安全的跨域请求,默认开启了CSRF
保护,参考Jenkins远程API访问
Jenkins的CSRF配置可以在「系统管理」——> 「全局安全配置」——> 「CSRF Protection」相关配置中关闭此保护,跨站请求伪造这是一个很常见的安全问题,为了安全起见建议不关闭。如果关闭,这里的内容可以略过。
当Jenkins
开启CSRF
保护后,可以通过固定的接口获得一个安全的Crumb
以便于通过API
操作Jenkins
,以curl
请求为例,请求的可选方式一般是两种,如下
方法一:
curl -u <username>:<password> ‘https://jenkins.ssgeek.com/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)‘
Jenkins-Crumb:dc78dfb9615fb56bbf2001fb99c64dbd3331c5e14c8d4edd54722e7ca790529e%
方法二:
curl -u <username>:<password> ‘https://jenkins.ssgeek.com/crumbIssuer/api/json‘
{"_class":"hudson.security.csrf.DefaultCrumbIssuer","crumb":"52d605f43328f15303c2e68eb492b9656e229ce124c2f5f2e39b6f552f54e4ac","crumbRequestField":"Jenkins-Crumb"}%
以上两种方式都可以获取一个Crumb
,然后就能带着它去请求Jenkins
的API
了
curl -u <username>:<password> -X POST -H "Jenkins-Crumb:b220147dbdf3cfebbeba4c29048c2e33" -d <data> ‘https://jenkins.ssgeek.com/<jenkins api url>‘
在官方文档的描述中有这样一句话:API tokens are preferred instead of crumbs for CSRF protection.
意为在开启了CSRF
的情况下,首选的是通过API token
操作而不是crumb
,这里的API token
指的就是Jenkins
中用户的API token
可以通过「用户」——> 「设置」——> 「API Token」——> 「添加新Token」来获得一个api token
,有了这个Token
之后,以curl
请求为例操作Jenkins
的API
方式如下
curl -u user_id:user_api_token -X POST -d <data> ‘https://jenkins.ssgeek.com/<jenkins api url>‘
参考上面的文档资料使用Jenkins REST API恢复暂停的管道
对于input
有这样的api
接口地址可以使用,用于将输入发送到等待的输入步骤。url
格式如下
http://<JenkinsURL>/<JobURL>/<Build#>/input/<InputID>/submit
需要满足的条件
如果Jenkins
启用了CSRF
保护,则您需要使用Crumb
或API Token
请求通过POST
方式发送
需要提供参数名为proceed
的值,并且以OK
作为参数值
为了提供数据,需要带有json
格式的参数,这些参数就是在input
阶段需要接收的参数,格式为
{
"parameter":[
{
"name":"param1",
"value":"valueOfParam1"
},
{
"name":"param2",
"value":"valueOfParam2"
}
]
}
如果没有发送有效的json
参数,则流水线也将继续进行,只是不会获得任何参数(这也可能导致流水线最终执行失败),如果成功则返回302
状态码并重定向到用户界面
必须填写input id
,因此要从外部连接到的input
步骤配置唯一的id
也可以使用下面的url,如果流水线成功,则返回状态码为200
且响应为空
http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/wfapi/inputSubmit
其他可用的api
接口地址以及作用
http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/input/<INPUT_ID>/abort
http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/input/<INPUT_ID>/proceedEmpty
对于本文中我的需求,只需要在input
执行时自动确认且无需传入任何参数即可,因此使用的接口地址为上面的最后一种(其余接口地址未测试)
为了实现在input
执行时自动确认,需要对流水线的input
部分进行改造,加入一个固定的id
即可
由于定义的id
都是固定的,因此可以利用脚本对所有的流水线涉及到这种input
的部分批量更新,这里就不列出具体方法了
最终我的流水线调整如下
stage(‘Deploy to prod‘){
when {
beforeInput true
environment name: ‘PerformType‘, value: ‘Deploy‘
}
options {
timeout(time:60, unit:‘SECONDS‘)
}
input {
message "确认要部署到线上环境吗?"
id "CustomId"
}
steps{
script{
try {
...
}
catch (exc) {
...
throw(exc)
}
}
}
}
经过上面的推理和测试,解决了通过API
自动执行input
进行流水线确认的问题
这里还剩下最后一个问题,通过测试发现,想要自动执行input
过程,其接口对应的url
地址并不是一直存在的,而是在流水线执行开始后到达input
的时候才会出现,出现时通过浏览器访问查看如下
而其余时间发送请求都会返回404
状态码,此时是无法接收post
请求的,因此想要自动化执行input
并不只是简单的向接口发送POST
请求了
我这里的解决思路:
在发送流水线开始执行的请求后,立即通过代码循环请求并判断接口地址返回的状态码是否是200
如果不是,那么表示流水线还没执行到这里;如果是,就可以完美的向这个地址发送自动执行的请求了
以python
语言调用Jenkins api
为例,用到了python-jenkins
这个包,在触发构建时使用build_job
这个方法,这个方法返回值刚好是job
任务的build number
,这恰好是接口地址组成中需要的一部分
好了,上最终的部分代码
def auto_job_input(self, server_url, job_name, build_number):
"""
根据input阶段生成的url http状态码,判断当前job流水线运行的stage否进行到了input步骤
自动执行input or 继续判断
:param job_name:
:param build_number:
:return:
"""
# https://jenkins.ssgeek.com/job/input-demo/64/input
get_url = server_url + "/job/" + job_name + "/" + str(build_number) + "/input"
# https://jenkins.ssgeek.com/job/input-demo/64/input/CustomId/proceedEmpty
post_url = get_url + "/CustomId/proceedEmpty"
s = requests.Session()
res_code_get = s.get(url=get_url, auth=(‘user_id‘, ‘user_token‘)).status_code
while res_code_get != 200:
res_code_get = s.get(url=get_url, auth=(‘user_id‘, ‘user_token‘)).status_code
res_code_post = s.post(url=post_url, auth=(‘user_id‘, ‘user_token‘), data=None).status_code
return res_code_post
关键部分代码量很少,利用request
并且携带认证参数进行请求,如果有大佬有更好的方案欢迎与我交流
到这里,通过一步步推理演进,在流水线中input
的自动化执行就完美实现了,最终既实现了调用api
触发自动构建并执行input
进行自动确认,同时也保留了原流水线的input
设计,对原有流水线只需要做很小的调整。
Jenkins API+Pipeline深度实践之input的自动化
标签:全局 通过 导致 contain shang 默认 构建 groovy row
原文地址:https://www.cnblogs.com/ssgeek/p/14585567.html