远程触发Jenkins构建后,请检查作业状态。

29

我有一个脚本可以远程通过令牌触发Jenkins上的作业。以下是我的脚本:

JENKINS_URL='http://jenkins.myserver.com/jenkins'
JOB_NAME='job/utilities/job/my_job'
JOB_TOKEN='my_token'

curl "${JENKINS_URL}/${JOB_NAME}/buildWithParameters?token=${JOB_TOKEN}"

运行后,我得到了以下的响应:

* Hostname was NOT found in DNS cache
*   Trying 10.5.187.225...
* Connected to jenkins.myserver.com (10.5.187.225) port 80 (#0)
> GET /jenkins/job/utilities/job/my_job/buildWithParameters?token=my_token HTTP/1.1
> User-Agent: curl/7.37.1
> Host: jenkins.myserver.com
> Accept: */*
> 
< HTTP/1.1 201 Created
* Server nginx/1.6.2 is not blacklisted
< Server: nginx/1.6.2
< Date: Tue, 03 Feb 2015 23:40:47 GMT
< Content-Length: 0
< Location: http://jenkins.myserver.com/jenkins/queue/item/91/
< Connection: keep-alive
< Cache-Control: private
< Expires: Wed, 31 Dec 1969 16:00:00 PST
< 
* Connection #0 to host jenkins.myserver.com left intact

我注意到它在头部返回了队列URL:http://jenkins.myserver.com/jenkins/queue/item/91。但我不知道如何使用这个返回URL。

1)我想知道是否有人知道我该如何检查刚创建的工作的状态?

2)由于上面的响应没有返回工作编号,因此我无法真正使用此API调用:

curl http://jenkins.myserver.com/jenkins/job/utilities/job/my_job/8/api/json

想要检查工作状态。那么在从上面的响应中获取位置URL后,我在哪里可以获得工作名称和工作编号?

谢谢

6个回答

39

我使用Jenkins服务器的轮询解决了这个问题。当远程启动作业时,返回头中会包含作业队列URL。利用这个URL,可以进行更多的API调用以获取状态。

步骤:

  • 启动作业
  • 解析返回的 'Location' 头
  • 轮询队列以查找要启动的作业
    • 作业队列条目在其JSON或XML中具有带有作业编号的 'executable' 条目,一旦启动即可显示
  • 轮询作业状态等待结果

我使用Python和Requests模块完成了这个过程。

#!/usr/bin/python

import requests
import re
import sys 
import json
import time

# secs for polling Jenkins API
#
QUEUE_POLL_INTERVAL = 2 
JOB_POLL_INTERVAL = 20
OVERALL_TIMEOUT = 3600 # 1 hour

# job specifics: should be passed in
auth_token = 'buildmaster:173223588624f980c3AAA68d4d8efe0c'
jenkins_uri = '192.168.115.187:8080'
job_name = 'rf_systest'
build_token = 'rf_systest_auth_token'

# start the build
#
start_build_url = 'http://{}@{}/job/{}/build?token={}'.format(
        auth_token, jenkins_uri, job_name, build_token)
r = requests.post(start_build_url)

# from return headers get job queue location
#
m = re.match(r"http.+(queue.+)\/", r.headers['Location'])
if not m:
    # To Do: handle error
    print "Job starte request did not have queue location"
    sys.exit(1)

# poll the queue looking for job to start
#
queue_id = m.group(1)
job_info_url = 'http://{}@{}/{}/api/json'.format(auth_token, jenkins_uri, queue_id)
elasped_time = 0 
print '{} Job {} added to queue: {}'.format(time.ctime(), job_name, job_info_url)
while True:
    l = requests.get(job_info_url)
    jqe = l.json()
    task = jqe['task']['name']
    try:
        job_id = jqe['executable']['number']
        break
    except:
        #print "no job ID yet for build: {}".format(task)
        time.sleep(QUEUE_POLL_INTERVAL)
        elasped_time += QUEUE_POLL_INTERVAL

    if (elasped_time % (QUEUE_POLL_INTERVAL * 10)) == 0:
        print "{}: Job {} not started yet from {}".format(time.ctime(), job_name, queue_id)

# poll job status waiting for a result
#
job_url = 'http://{}@{}/job/{}/{}/api/json'.format(auth_token, jenkins_uri, job_name, job_id)
start_epoch = int(time.time())
while True:
    print "{}: Job started URL: {}".format(time.ctime(), job_url)
    j = requests.get(job_url)
    jje = j.json()
    result = jje['result']
    if result == 'SUCCESS':
        # Do success steps
        print "{}: Job: {} Status: {}".format(time.ctime(), job_name, result)
        break
    elif result == 'FAILURE':
        # Do failure steps
        print "{}: Job: {} Status: {}".format(time.ctime(), job_name, result)
        break
    elif result == 'ABORTED':
        # Do aborted steps
        print "{}: Job: {} Status: {}".format(time.ctime(), job_name, result)
        break
    else:
        print "{}: Job: {} Status: {}. Polling again in {} secs".format(
                time.ctime(), job_name, result, JOB_POLL_INTERVAL)

    cur_epoch = int(time.time())
    if (cur_epoch - start_epoch) > OVERALL_TIMEOUT:
        print "{}: No status before timeout of {} secs".format(OVERALL_TIMEOUT)
        sys.exit(1)

    time.sleep(JOB_POLL_INTERVAL)

输出:

Tue Jan 30 16:24:08 2018: Job rf_systest added to queue: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/queue/item/164/api/json
Tue Jan 30 16:24:39 2018: Job rf_systest not started yet from queue/item/164
Tue Jan 30 16:25:00 2018: Job started URL: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/job/rf_systest/79/api/json
Tue Jan 30 16:25:01 2018: Job: rf_systest Status: None. Polling again in 20 secs
Tue Jan 30 16:25:21 2018: Job started URL: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/job/rf_systest/79/api/json
Tue Jan 30 16:25:21 2018: Job: rf_systest Status: None. Polling again in 20 secs
Tue Jan 30 16:25:41 2018: Job started URL: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/job/rf_systest/79/api/json
Tue Jan 30 16:25:41 2018: Job: rf_systest Status: None. Polling again in 20 secs
Tue Jan 30 16:26:01 2018: Job started URL: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/job/rf_systest/79/api/json
Tue Jan 30 16:26:01 2018: Job: rf_systest Status: None. Polling again in 20 secs
Tue Jan 30 16:26:21 2018: Job started URL: http://buildmaster:173223588624f980c344668d4d8efe0c@192.168.115.187:8080/job/rf_systest/79/api/json
Tue Jan 30 16:26:21 2018: Job: rf_systest Status: SUCCESS

一旦Jenkins队列的作业开始,就从中获取JSON:

{
    "_class": "hudson.model.Queue$LeftItem",
    "actions": [
        {
            "_class": "hudson.model.CauseAction",
            "causes": [
                {
                    "_class": "hudson.model.Cause$RemoteCause",
                    "addr": "10.20.30.60",
                    "note": null,
                    "shortDescription": "Started by remote host 10.20.30.60"
                }
            ]
        }
    ],
    "blocked": false,
    "buildable": false,
    "cancelled": false,
    "executable": {
        "_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
        "number": 45,
        "url": "http://192.168.115.187:8080/job/rf_systest/45/"
    },
    "id": 95,
    "inQueueSince": 1517342648136,
    "params": "",
    "stuck": false,
    "task": {
        "_class": "org.jenkinsci.plugins.workflow.job.WorkflowJob",
        "color": "blue_anime",
        "name": "rf_systest",
        "url": "http://192.168.115.187:8080/job/rf_systest/"
    },
    "url": "queue/item/95/",
    "why": null
}

3
这个应该是被接受的答案,找到队列ID并查询API,最终获取构建ID。http://jenkinsurl/queue/item/43815将返回404,然而,http://jenkinsurl/queue/item/43815/api/json将返回构建号码。 - Larry Song
1
我为什么在使用api/json后缀时会收到404错误? - khc
提示:如果您不需要“安静期”,可以将作业的“安静期”设置为零,从而缩短在 while True: 中花费的时间。 (我的默认值为5秒) - Maarti
1
我得到了以下错误信息:c:\temp>py test.py Traceback (most recent call last): File "c:\temp\test.py", line 3, in <module> import requests ModuleNotFoundError: No module named 'requests' - sero
1小时!wy wy wy - Abdennour TOUMI
显示剩余2条评论

7

我曾经遇到过使用rest api获取状态的类似问题。
这是我的解决方案(它是一个不够完善且不太稳定的解决方案!):

#Ex. http://jenkins.com/job/test
JOB_URL="${JENKINS_URL}/job/${JOB_NAME}"

#here you can ask for next build job number
function getNextBuildNr(){
  curl --silent ${JOB_URL}/api/json | grep -Po '"nextBuildNumber":\K\d+'
}    

# this will request the Status of job
function getBuildState(){
  buildNr=$1
  curl --silent ${JOB_URL}/${buildNr}/api/json | grep -Po '"result":\s*"\K\w+'
}

#this will wait for your Job state, by polling Jenkins every second
function waitForJob() {
  buildNr=$1
  state=""

  while [ "${state}" == "" ]
  do
     sleep 1
     state=$(getBuildState ${buildNr})
     echo -n '.'
  done

  echo -e "\n"
}

#now you can run and build
BUILD_NR=$(getNextBuildNr)

# input here your code/function to trigger the job

waitForJob ${BUILD_NR}
BUILD_STATE=$(getBuildState ${BUILD_NR})
echo "$BUILD_STATE"

7
您可以使用Jenkins API进行此操作。以下是一个Python脚本示例:
import json
import requests
import time



job_name = "testjob" .  #Give your job name here


def jenkins_job_status(job_name):

        try:
                url  = "https://your_jenkins_endpoint/job/%s/lastBuild/api/json" %job_name   #Replace 'your_jenkins_endpoint' with your Jenkins URL
                while True:
                        data = requests.get(url).json()
                        if data['building']:
                                time.sleep(60)
                        else:
                                if data['result'] == "SUCCESS":

                                        print "Job is success"
                                        return True
                                else:
                                        print "Job status failed"
                                        return False


        except Exception as e:
                print str(e)
                return False




if __name__ == "__main__":

        if jenkins_job_status(job_name):

                print "Put your autmation here for 'job is success' condition"

        else:
                print "Put your autmation here for 'job is failed' condition" 

请参考http://www.easyaslinux.com/tutorials/devops/how-to-check-build-status-of-jenkins-job-using-python-script/,详细解释如何使用Python脚本检查Jenkins作业的构建状态。


5
当您触发作业时,该作业将被放置在队列中。实际的构建仅在它开始运行并且此时构建获得构建编号时才创建。如果所有执行器都很忙,则有时需要很长时间才能创建和开始运行构建。
唯一获取触发作业的构建号的方法是使用Jenkins CLI的“build”命令。如果使用-w选项,该命令将一直等待直到构建开始,然后打印“Started build #N”。
实际上您不需要java cli.jar,只需一个ssh客户端就足够了。请参见https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+SSH 除此之外,没有已知的解决方案。您可能能够搜索构建并找到一个在您触发作业时触发的构建,但那是很多工作。

5
这个限制还存在吗?这是使用 Rest API 的一个重要缺点,因为 CLI 不是实际可行的替代方案。 - raffian
这不是获取构建号的唯一方法。请继续阅读其他答案。 - froblesmartin
3
因为这个回答是错误的,所以被踩了。请参见下面的https://dev59.com/614c5IYBdhLWcg3wHHCY#48531874使用远程HTTP API的答案。 - benthehutt

2

0
一个完全支持Groovy的解决方案可能是以下这样的:
 import groovy.json.JsonSlurper



    while(true){
            sh """
                   curl -X POST -u "admin:xxx" "https://another-jenkins.com/job/jobName/build"
               """

               def response = sh(script: """ curl -X GET -u "admin:xxx" "https://another-jenkins.com/job/jobName/lastBuild/api/json" """, returnStdout: true)

               def jsonSlurper = new JsonSlurper()
               def obj = jsonSlurper.parseText(response)

               if (!obj.building){

                   if(obj.result=="FAILURE"){
                    println("remote jenkins failing")
                       //throw new Exception("QA JENKINS returns failure.")
                   }
                   break;
               }
                
                sleep(3000)
       }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接