About 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.

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>
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


5 + five =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books