在前面远程启动Jenkins工程的文章中,我们已经初步的接触到了API方式的调用,这种方式是通过网络请求进行的,我们前面使用的jenkinsapi库,以及其他的诸如Python-Jenkins、api4jenkins,aiojenkins等库都是实现的这个功能。对于上一篇文章中的断开节点链接,jenkinsapi库里是没有这个功能的,那么我们是不是也可以去寻找api实现他。
如果还是用的Python代码的话,那么事情就变成了使用requests库来实现功能了,更为通用的功能是将其写入js中,这样哪个语言都可能集成的了。
身份认证
身份认证可以使用requests库里的HTTPBasicAuth
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth(username='bob', password='110c70ea8f41063e377aca53007a1ca2e4')
这个类似于创建Jenkins实例时输入的账号和token,并且是默认use_crumb为True的情况。
jks = Jenkins('http://127.0.0.1:8080/', username='bob', password='110c70ea8f41063e377aca53007a1ca2e4',
use_crumb=True)
后续在发起请求的时候,我们只要在请求方法调用参数里加上auth=auth即可。
断开节点连接的api和其他api的查找方法
注:Jenkins中节点和代理一直用的2套中英文,但是实际看来是一个东西。
查询类的api其实很容易找到,只需要看Jenkins页面,右下角有REST API的就是可以执行远程操作的功能。
这个页面里面列举了一些基本的api方式,但明显是不全的,我们要的功能并不存在。
因为是计划用requests来执行操作,所以我按照requests的思维,选择去浏览器抓取工作链接。
进入到断开链接的页面后打开控制台-网络
点击是按钮
可以看到第一个跳出来的是doDisconnect请求。
复制这个请求。选择复制为cURL(bash) 的方式
进入curl converter页面进行转换即可。
节点断开连接
关键区域的代码如下:
data = {
'offlineMessage': '', 'Jenkins-Crumb': 'b73836120dc03620b4bd46d5e1147b6cdd08879096b594a61a9a50701d45fba5',
'json': '{"offlineMessage": "", "Jenkins-Crumb": "b73836120dc03620b4bd46d5e1147b6cdd08879096b594a61a9a50701d45fba5"}',
'Submit': '是'
}
response = requests.post('http://127.0.0.1:8080/computer/test4/doDisconnect', cookies=cookies, headers=headers, data=data, verify=False, )
拉下来自己调试,经过分析,data里除了offlineMessage,其他的都是不必要的。
将原有节点重新连接后,通过代码进行断开。
完整代码如下:
# coding:utf-8
import requests
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth(username='bob', password='110c70ea8f41063e377aca53007a1ca2e4')
data = {
'offlineMessage': '通过requests提交关闭',
}
response = requests.post('http://127.0.0.1:8080/computer/test4/doDisconnect', auth=auth,data=data)
执行后界面显示
断开后如果代理能够被连接,会被断开重试的机制重新连接上,这和在网页上点击断开的效果是一样的,所以并不是代码的异常。
启动代理链接
如果需要启动代理。我们可以点击这个启动代理的按钮,然后提取浏览器的请求。
请求的路由是
POST /computer/test4/launchSlaveAgent
data里没有实际的信息。可以不用。
response = requests.post('http://127.0.0.1:8080/computer/test4/launchSlaveAgent', auth=auth)
这个调试的时候速度要快,不然等会儿节点自己就连接上了
节点临时上下线
同样的,临时上下线的功能也是这样提取
临时上下线:
POST /computer/test4/toggleOffline
数据data为
'offlineMessage': 'message',
重新运行一遍就又临时的上线了。这个是共用的同一个路由。
闲置状态查询
是否闲置的话就是直接查询节点状态
GET /computer/test4/api/json
这里因为api/python的结果不建议用eval直接转换,并且为了其他语言读者更加通用,这里使用的是api/json。读取结果中的idle键的值就可以了。
需要注意的是节点的idle为True的时候并不只是没任务,连接断开或者临时断开都会导致节点是闲置的。这种代表了我们不能光看机器闲置就觉得机器是可用的,必须要机器既在线又是闲置才是可以被任务使用的。
配置查询
在浏览器里显示的是
GET /computer/test4/configure
但很明显这种GET的只能拿到一个网页数据,从REST API页面的介绍中可以看到实际应该是这个
GET /computer/test4/config.xml
实际得到的是一个xml格式的字符串
修改配置
在网页端保存数据截取记录,获得的路由是
POST /computer/test4/configSubmit
转换后的数据字段极为复杂。
除了能够批量替换的修改,不建议这样使用。
还是通过下面这个请求来处理
POST /computer/test4/config.xml
jenkinsapi的库也是这样处理的,但是对于新版本Jenkins而言,他缺少了2个关键的请求头参数。
分别是Content-Length和Host,导致库无法正常实现这个功能。
于是我们实现的代码是:
old_config = """<?xml version="1.1" encoding="UTF-8"?>
<slave>
<name>test4</name>
<description></description>
<remoteFS>/data</remoteFS>
<numExecutors>5</numExecutors>
<mode>NORMAL</mode>
<retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
<launcher class="hudson.plugins.sshslaves.SSHLauncher" plugin="ssh-slaves@2.854.v7fd446b_337c9">
<host>127.0.0.1</host>
<port>10009</port>
<credentialsId>0f4ad930-938b-4440-9d0d-14aae7951b61</credentialsId>
<jvmOptions>-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Dnative.encoding=UTF-8</jvmOptions>
<launchTimeoutSeconds>60</launchTimeoutSeconds>
<maxNumRetries>10</maxNumRetries>
<retryWaitTime>15</retryWaitTime>
<sshHostKeyVerificationStrategy class="hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy"/>
<tcpNoDelay>true</tcpNoDelay>
</launcher>
<label>test</label>
<nodeProperties/>
</slave>"""
new_config = old_config.replace('<numExecutors>2</numExecutors>', '<numExecutors>3</numExecutors>')
raw_data = new_config.encode('utf-8')
content_length = len(raw_data)
host = '127.0.0.1'
headers = {
'Content-Length': str(content_length),
'Host':host
}
response = requests.post('http://127.0.0.01:8080/computer/test4/config.xml', auth=auth,
data=raw_data, headers=headers)
print(response.status_code)
print(response.text)
注意这里的config字符串要符合xml规范且头尾无多余空格与换行。修改原有的配置可以通过xml节点进行操作,也可以通过替换字符串操作。最终是个bytes类型。
正常更新的响应体是空的,状态码是200。
可以看到节点的配置修改记录里面出现了我们的远程修改。经过调试可以发现,当修改没有差异的时候,不会发生记录。
删除节点
POST /computer/test4/doDelete
执行完就把节点删除了。重复执行只会得到404的响应状态码。
增加节点
POST /computer/doCreateItem
node_name = 'test_node_1'
params = {
'name': node_name, 'type': 'hudson.slaves.DumbSlave$DescriptorImpl',
'json': '{"name": "%s", "nodeDescription": null, "numExecutors": 2, "remoteFS": "/var/lib/jenkins", "labelString": null, "mode": "NORMAL", "retentionStrategy": {"stapler-class": "hudson.slaves.RetentionStrategy$Always", "$class": "hudson.slaves.RetentionStrategy$Always"}, "type": "hudson.slaves.DumbSlave", "nodeProperties": {"stapler-class-bag": "true"}, "launcher": {"stapler-class": "hudson.slaves.JNLPLauncher"}}'%node_name
}
print(params)
from urllib.parse import urlencode
data = {
'json': urlencode(params)
}
response = requests.post(f'http://127.0.0.1:8080/computer/doCreateItem', auth=auth, data=data,params=params)
因为jnlp的默认节点用的不多,所以这里在配置项目只设置了名称,建议后续依靠其他节点的配置进行修改。 这个请求比较特殊,一定要把参数在data和params都放一遍。