Enterprise Java

Using Jenkins / Hudson remote API to check jobs status

While working on my talk Writing a Hudson / Jenkins plugin (for EclipseCon NA 2014), I wanted to publish blog posts about the ideas mentioned in the talk; in this post I explain how you can interact with your CI server without using the web interface.

The Jenkins / Hudson remote API can be very convenient to quickly gather jobs status (and even to create or launch jobs ! but I won’t cover that aspect in this blog post); let’s have a look at some examples.

Have a look at the CLI to automate Jenkins configuration tasks.

It’s available at http://hudson-or-jenkins/cli : download the hudson-cli.jar or jenkins-cli.jar and get started with this first command :

 $ java -jar jenkins-cli.jar -s http://jenkins.terracotta.eur.ad.sag:8080/ help

Recently, I had to replace 50 jobs with a matrix job : once I created the matrix job, we decided to de activate the previous 50 jobs (before removing them for good)

Using the CLI, I could quickly login :

 $ java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ login --username anthony --password password

then get the list of jobs :

 $ java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ list-jobs

I saved the list of the 50 jobs I wanted to de activate in a text file, and I looped through this list :

 $ while read p; do java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ disable-job $p; done < list_of_jobs.txt

More efficient than going through the UI, isn’t it ?

Every URL can be represented as XML or JSON

As explained in the Jenkins documentation and Hudson documentation, you just need to append /api/xml or /api/json or /api/python to any Jenkins URL to see the corresponding representation

You can configure the responses adding few arguments to the URL :

Depth

The default depth is 0, to get more details about your jobs, builds, etc, set the depth to 1 : http://ci.jruby.org/api/xml?depth=1

This argument can be harmful to your CI server when bigger than 1 (it gets really deep past 1 …) since the responses tend to become really large.

Tree

The tree argument allows you to select some portion of the response http://ci.jruby.org/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]

xpath and exclude (XML only)

Those arguments are probably the most powerful ones, sadly they are only available for xml responses :

If I only want to display jobs that were not successful, I can simply use this url : http://ci.jruby.org/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]&exclude=hudson/job[lastBuild[result=’SUCCESS’]]

And if I only want to see jobs with a name starting with “jruby”, I can apply Xpath functions to the url : http://ci.jruby.org/api/xml?xpath=hudson/job[starts-with(name,’jruby’)]&wrapper=mywrap

Few Jenkins and Hudson public instances URLs

It’s pretty easy to find some public Jenkins and Hudson instances to practice your latest URL filtering (google for “Hudson Dashboard” or “Jenkins Dashboard”), but it’s harder to find up to date and meaningful (few jobs) instances :

Jenkins :

Hudson :

That said, try your local instance first!

Jenkins and Hudson remote API scripts

The main interest of the Jenkins/Hudson remote API is to interact with it from your own software : I gather here some examples in few scripting languages

Groovy Script to parse Jenkins Hudson build results

class BuildParser {
  static void main(String[] args) {
    if (args.length != 1) {
      println("Please run the script with a Jenkins or Hudson url as the only argument\n Example : groovy BuildParser.groovy http://ci.jruby.org");
      return;
    }
    def url = args[0];
    def xmlInputFilteringSuccess = new XmlParser().parse(url + "/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]&exclude=hudson/job[lastBuild[result=%27SUCCESS%27]]");
    def xmlInputNoFilter = new XmlParser().parse(url + "/api/xml?depth=1&tree=jobs");
 
    def jobs = xmlInputFilteringSuccess.job;
    println(jobs.size() + " jobs out of " + xmlInputNoFilter.job.size() + " are currently failing")
    jobs.each(
        {
          println(
              it.displayName.text() +
              " result is " + it.lastBuild.result.text())
        }
    )
  }
}

Python Script to parse Jenkins Hudson build results

import ast
import urllib
import sys

if len(sys.argv) != 2:
  print "Please run the script with a Jenkins or Hudson url as the only argument\n Example : python BuildParser.py http://ci.jruby.org"
  sys.exit(1)

url = str(sys.argv[1])
print url

xml_input_no_filter = ast.literal_eval(urllib.urlopen(url + "/api/python?depth=1&tree=jobs[displayName,lastBuild[result]]").read())

all_jobs = xml_input_no_filter['jobs']
non_successful_jobs = [row for row in all_jobs if 'SUCCESS' != row['lastBuild']['result']]

print(str(len(non_successful_jobs)) + " jobs out of " + str(len(all_jobs)) + " are currently failing")

for (i, item) in enumerate(non_successful_jobs):
  print "Job name : " + item['displayName'] + "Result : " + item['lastBuild']['result']

JavaScript code to parse Jenkins Hudson build results

<!-- Strongly inspired by https://gist.github.com/alexschwartz/912787 -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Build Parser</title>
 
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
 
  <script type="text/javascript">
    $(document).ready(function(){
      var baseUrl;
      $('button').click(function(){
        baseUrl = $("#baseUrl").val();
        $("#jobUrl").html(baseUrl)
 
        var success = function(json) {
          var allJobs = json["jobs"];
          var nonSuccessfulJobs = allJobs.filter(function( job ) {
            return job["lastBuild"] != null && job["lastBuild"]["result"] != "SUCCESS";
          });
 
          $("#downstream").html(nonSuccessfulJobs.length + " out of " + allJobs.length + " are currently failing");
          $.each(nonSuccessfulJobs, function( index, value ) {
            $("#downstream").append("<br />Job name : " + value["displayName"] + " : "+ value["lastBuild"]["result"] );
          });
        };
 
        $.ajax({
          url: baseUrl + "/api/json",
          data: "depth=1&tree=jobs[displayName,lastBuild[result]]&jsonp=callBack",
          jsonpCallback: "callBack",
          dataType: 'jsonp',
 
          success: success
        });
      });
    });
  </script>
</head>
<body marginwidth="50" marginheight="50" topmargin="50" leftmargin="50">
<h3>Input Data</h3>
 
Hudson/Jenkins Base URL:
<input type="text" id="baseUrl" value="https://hudson.eclipse.org/hudson/" size="80" /><br/>
 
<button>update</button><br />
 
<h2>Output</h2>
 
<h3>Failing Jobs</h3>
<div id="downstream">
</div>
 
</body></html>

Anthony Dahanne

Anthony Dahanne is a Java software developer for 8 years, his favorite topics are Android, building tools, Continuous Integration and, of course, core Java development. Working for Terracotta, he currently implements the REST management interface for EhCache.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
chitra
chitra
7 years ago

Do we have pom file that can download necessary jenkins core and other required libraries – so that we can write groovy without compilation and explore more classes and their methods?

Please guide me

Back to top button