Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check Jenkins job status after triggering a build remotely

I have a script to trigger a job on Jenkins remotely using a token. Here is my script:

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}"

After I run it, I get following response:

* 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

I noticed that it returns the queue url in the header: http://jenkins.myserver.com/jenkins/queue/item/91. But I don't know how I should use this return url.

1) I am wondering if anyone knows how I can check the status for the job that I just created?

2) Since the above response does not return the job #, I can't really use this api call:

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

to check for status. So where can I get the job name and job number after I get the location url from the above response?

Thanks

like image 598
Nam Nguyen Avatar asked Feb 03 '15 23:02

Nam Nguyen


People also ask

How do I trigger a Jenkins job in remote Jenkins?

Create a remote Jenkins build trigger in three stepsCreate a Jenkins build job and enable the Trigger builds remotely checkbox. Provide an authentication token; This can be any text string of your choice. Invoke the Jenkins build URL to remotely trigger the build job.

How do you call a Jenkins build from outside Jenkins?

Install Generic Webhook Trigger plugin. Select generic webhook trigger in build trigger actions. Generate a random string and paste in token. Now your job can be triggered with a http request to the following url.

Which command is used to trigger build remotely in Jenkins?

In the new Jenkins Pipeline, under Build Triggers, select the checkbox Trigger builds remotely (e.g., from scripts). Then give Jenkins a token that will be required when triggering the build.

How do I trigger a Jenkins job on a remote server?

The most common use cases are triggering a build from a scheduler or another automated job. Here in this post we’ll see how we can trigger a job on a remote Jenkins server. To trigger a build, we simply need to http POSTto the specific job API. POST to the buildAPI for simple builds, and to buildWithParametersfor the jobs that need some parameters.

How to get the status of the build in Jenkins?

In order to get the status of the build, you must follow the three steps below. Jenkins build, once triggered, will have the below flow: Job Triggered->Waits on Queue (Queue Number)->assign node for the build -> gets a Build Number STEP 3: Get the Build Number

How do I authenticate a Jenkins job?

You’ll need to use the “user-api-token”for authentication Job-authentication-token is an authorization token per job. For that, first you have to enable remote trigger of jobs from “Jenkins » Project » Job » Configure » Trigger builds remotely”.

What is Jenkins job?

Jenkinsis one of the oldest & most popular CI (Continuous Integration) servers, and many teams still configure and run their daily and ad-hoc build jobs with Jenkins. The build workflows, or simply jobs, are set of runnable commands that generally executes a complete CI-build.


3 Answers

I solved this problem using polling of the Jenkins server. When a job is started remotely the return headers has the job queue URL. Using this one can make more API calls to get status.

Steps:

  • start the job
  • parse return 'Location' header
  • poll the queue looking for job to start
    • job queue entry will have an 'executable' entry in its json or xml with job number once it starts
  • poll the job status waiting for a result

I used python and the Requests module to do this

#!/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)

Output:

Tue Jan 30 16:24:08 2018: Job rf_systest added to queue: http://buildmaster:[email protected]: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:[email protected]: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:[email protected]: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:[email protected]: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:[email protected]: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:[email protected]:8080/job/rf_systest/79/api/json
Tue Jan 30 16:26:21 2018: Job: rf_systest Status: SUCCESS

JSON from a Jenkins queue once its job has started:

{
    "_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
}
like image 92
P. Hawkins Avatar answered Oct 23 '22 17:10

P. Hawkins


I had similar problem to get state with rest api only.
this was my solution (it is a weak and not stable solution!):

#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"
like image 6
ya_dimon Avatar answered Oct 23 '22 18:10

ya_dimon


You can use Jenkins API for this. A sample Python script:

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" 

Refer http://www.easyaslinux.com/tutorials/devops/how-to-check-build-status-of-jenkins-job-using-python-script/ for detailed explanation

like image 5
Nijil Avatar answered Oct 23 '22 17:10

Nijil