【问题标题】:Check Jenkins job status after triggering a build remotely远程触发构建后检查 Jenkins 作业状态
【发布时间】:2015-04-03 08:44:21
【问题描述】:

我有一个脚本可以使用令牌远程触发 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)由于上面的响应没有返回job#,所以我不能真正使用这个api调用:

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

检查状态。那么从上面的回复中得到位置 url 后,我在哪里可以得到职位名称和职位编号呢?

谢谢

【问题讨论】:

    标签: jenkins build jenkins-plugins jenkins-cli


    【解决方案1】:

    我通过轮询 Jenkins 服务器解决了这个问题。远程启动作业时,返回标头具有作业队列 URL。使用这个可以进行更多的 API 调用来获取状态。

    步骤:

    • 开始工作
    • 解析返回“位置”标头
    • 轮询队列以查找作业开始
      • 一旦启动,作业队列条目将在其 json 或 xml 中包含一个带有作业编号的“可执行”条目
    • 轮询等待结果的作业状态

    我使用 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
    }
    

    【讨论】:

    • 非常感谢!它非常有用。一个快速的问题,什么是“为什么”:null?我正在寻找一种在作业完成后传递百分比结果值的方法,你知道这是否可以通过响应 json 实现吗?再次感谢。
    • 这个应该是公认的答案,找到队列id并查询它的API,最后得到build-id。 jenkinsurl/queue/item/43815 将返回 404,但是,jenkinsurl/queue/item/43815/api/json 将返回内部版本号。
    • 我得到 404 并带有 api/json 后缀的任何原因?
    • @khc 当作业被调度并从队列中清空时会发生这种情况,队列 id 是短暂的,应尽快使用。
    • 我收到:c:\temp&gt;py test.py Traceback (most recent call last): File "c:\temp\test.py", line 3, in &lt;module&gt; import requests ModuleNotFoundError: No module named 'requests'
    【解决方案2】:

    我遇到了类似的问题,只能通过 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"
    

    【讨论】:

      【解决方案3】:

      您可以为此使用 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/

      【讨论】:

        【解决方案4】:

        当您触发一个作业时,该作业将被放入队列中。实际构建仅在它开始运行时创建,此时构建会获得一个构建号。如果您的所有执行程序都很忙,有时可能需要很长时间才能创建构建并开始运行。

        触发作业时获取内部版本号的唯一方法是使用Jenkins CLI 的“构建”命令。如果您使用 -w 选项,该命令将在构建开始之前不会返回,然后它将打印“Started build #N”

        您实际上并不需要 java cli.jar,只需要一个 ssh 客户端就足够了。见https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+SSH

        除此之外,没有已知的解决方案。您也许可以搜索构建并找到一个在您触发作业时触发的构建,但这是很多工作。

        【讨论】:

        • @sti 这个限制还存在吗?在 CLI 不是实用替代方案的情况下,使用 Rest api 是一个主要缺点
        • 这不是获取内部版本号的唯一方法。继续阅读更多答案
        • 投反对票,因为这根本不正确。有关使用远程 HTTP API 的答案,请参阅下面的 stackoverflow.com/a/48531874/1011280
        【解决方案5】:

        对于需要从另一个 Jenkins 触发远程 Jenkins 作业的人,这里有一个很好的解决方案,可以触发远程作业并检查其状态:https://github.com/jenkinsci/parameterized-remote-trigger-plugin/blob/master/README_PipelineConfiguration.md

        就这么简单:

        def handle = triggerRemoteJob job: 'https://myjenkins:8080/job/JobWithoutParams', auth: TokenAuth(apiToken: '&lt;theApiToken&gt;', userName: '&lt;userName&gt;'), parameters: 'param1=abc\nparam2=xyz'

        【讨论】:

          【解决方案6】:

          完全启用 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)
                 }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-06-07
            • 2020-03-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-31
            • 1970-01-01
            相关资源
            最近更新 更多