全球超过100万台服务器在跑的Jenkins,多数人只用过它的Web界面。那个藏在地址栏里的/api/json,很多人部署三年都没碰过。
REST API(应用程序编程接口)是Jenkins最被低估的功能。触发构建、查状态、管插件、建任务、搭自定义仪表盘——全都能用HTTP请求搞定。不用装额外插件,开箱即用。
本文用代码说话。从curl到Python封装,再到一个能跑的健康度仪表盘,帮你把Jenkins从"鼠标密集型"工具变成可编程的基础设施。
第一步:拿到入场券
调用API需要两样东西:用户令牌和正确的认证头。在Jenkins用户设置里生成API Token,然后塞进环境变量:
export JENKINS_URL="http://localhost:8080"
export JENKINS_USER="admin"
export JENKINS_TOKEN="your-api-token"
认证方式选Basic Auth,用户名拼令牌当密码。curl里用-u参数,Python的requests库直接传元组。
先探探家底,看看Jenkins在跑什么:
curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/api/json" | jq \
'{mode: .mode, numExecutors: .numExecutors, jobs: [.jobs[] | {name: .name, color: .color}]}'
返回的JSON里,color字段就是状态:blue是成功,red是失败,aborted是手动终止。这个设计挺复古,但一眼能看懂。
触发构建更简单,POST过去就行:
curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" -X POST \
"$JENKINS_URL/job/my-project/build"
带参数的构建用buildWithParameters端点,参数直接拼URL:
curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" -X POST \
"$JENKINS_URL/job/deploy/buildWithParameters?ENVIRONMENT=staging&VERSION=2.1.0"
注意这里用了&转义,实际写代码时换成&。Jenkins对参数顺序不敏感,但大小写敏感。
第二步:封装成能复用的Python类
curl适合一次性操作,要集成到工作流还得上代码。下面这个JenkinsClient类覆盖了日常80%的需求:
class JenkinsClient:
def __init__(self, url, user, token):
self.url = url
self.auth = (user, token)
初始化只存两个东西:根地址和认证元组。requests库会自动处理Basic Auth的Base64编码,不用手动算。
查任务列表用get_jobs(),返回的是个字典数组。每个任务有name、url、color三个核心字段:
def get_jobs(self):
resp = requests.get(f"{self.url}/api/json", auth=self.auth)
return resp.json()['jobs']
构建信息要分层查。先拿到任务,再点进具体构建号。lastBuild是个虚拟编号,永远指向最新一次:
def get_build_info(self, job, build_number):
resp = requests.get(f"{self.url}/job/{job}/{build_number}/api/json", auth=self.auth)
return resp.json()
触发构建分有无参数两种情况。有参数走buildWithParameters,用params字典传;无参数直接POST到/build:
def trigger_build(self, job, parameters=None):
if parameters:
resp = requests.post(f"{self.url}/job/{job}/buildWithParameters", params=parameters, auth=self.auth)
else:
resp = requests.post(f"{self.url}/job/{job}/build", auth=self.auth)
return resp.status_code in (200, 201)
状态码201表示构建已入队,200是立即执行。实际两者都算成功,队列深度取决于你的Executor数量。
最实用的是wait_for_build()。触发后轮询状态,直到构建完成或超时。默认5秒查一次,300秒封顶:
def wait_for_build(self, job, build_number=None, timeout=300):
if not build_number:
time.sleep(3)
build_number = self.get_last_build(job)['number']
start = time.time()
while time.time() - start < timeout:
info = self.get_build_info(job, build_number)
if not info.get('building', True):
return info
time.sleep(5)
raise TimeoutError(f"Build {build_number} timed out")
这个轮询逻辑可以优化。Jenkins支持Webhook回调,但配置门槛高。对于大多数内部CI场景,轮询够用了。
第三步:搭一个健康度仪表盘
有了封装好的客户端,可以干点Web界面做不到的事。比如一个纯文本的健康度报告,扔给企业微信或钉钉机器人:
jenkins = JenkinsClient('http://localhost:8080', 'admin', 'your-token')
for job in jenkins.get_jobs():
status = 'PASS' if job['color'] == 'blue' else 'FAIL' if 'red' in job['color'] else job['color']
print(f"{status:6s} | {job['name']}")
输出长这样:
PASS | backend-service
FAIL | frontend-build
aborted | legacy-migration
颜色转状态用了个嵌套三元表达式,不够Pythonic但够短。实际生产建议用枚举类,方便扩展。
完整部署流程可以串起来:触发、等待、拿结果、发通知。五行代码搞定:
jenkins.trigger_build('deploy', {'ENVIRONMENT': 'staging', 'VERSION': '2.1.0'})
result = jenkins.wait_for_build('deploy')
print(f"Build #{result['number']}: {result['result']}")
result['result']只有四种值:SUCCESS、FAILURE、ABORTED、UNSTABLE。UNSTABLE通常是测试通过但有警告,比如覆盖率不达标。
想再进一步,可以抓控制台日志做失败分析。get_console_output()返回纯文本,正则匹配"ERROR"或"FAILURE"关键字,自动归类失败原因。这比打开浏览器翻几百行日志快多了。
Jenkins的API设计不算现代,端点命名混乱、文档散落在各插件页面。但它稳定,8年前的脚本今天还能跑。对于已经重度依赖Jenkins的团队,与其折腾迁移,不如把API用透。
你的CI/CD流水线有多少环节还在手动点鼠标?第一个能自动化的,会是什么?
热门跟贴