OK, not quite as moving as Dave Goldberg's story, but this one also brought a (little) tear of joy to my eye. Here is a story I initially wrote for our internal blogs at SAS, to help show folks the benefit of REST-like web APIs.
In my previous life at SAS, I administered a Jenkins/Maven CI environment for a small team. We came upon a
nasty Maven bug. Maven is supposed to kill a forked JUnit process when it exceeds the allotted time, but Maven was was failing to kill the process. We were getting periodic unit tests failures (and therefore build failures) because these orphaned JUnit tests could lock resources, causing other unit tests to fail.
Let me describe how we worked around this problem using public APIs.
by hand
I created a solution in parts. First, I did things manually. I logged onto our CI build server and ran a ps(1) job,
ps --no-headers -flu $buildUser --columns 512 | grep -v grep | grep 'surefire/surefirebooter'
searching for running surefire processes, while at the same time checking the Jenkins console to see if it was idle. If I found such processes still running when no builds were running, I killed 'em.
by machine
Well, I could not always be available to do this, so of course I automated this. First, I write a script to scan the ps output and kill any running surefire jobs (~/bin/kill-surefire); it used ~/bin/surefire-processes which is basically the ps command above.
Next, I wrapped this in a job ~/bin/monitor-processes that we added to our crontab for the $buildUser user.
by api
But how to verify that no Jenkins builds were active? I don't want to kill a legit JUnit test that has not timed out. This is where public APIs provide the solution I needed. Jenkins is nice (unlike Flash applications...) in that all of its screens and panels are accessible via distinct URLs. For example:
Further, the content of every page is also accessible from an /api subpage, and you can request the content be delivered in XML or JSON. So, to check which jobs are running, we do the following:
curl --silent http://buildhost.domain:port/quietDown
This quiesces the server, so it will not start any new builds. Currently running builds, if any, may continue.
curl --silent http://buildhost.domain:port/computer/api/xml
and look for <idle>true</idle> in the output. (Technically, I should parse the XML, perhaps with xsltproc, instead of just using fgrep, but fgrep works just fine here.)
If there are no running builds in Jenkins, run ~/bin/kill-surefire
curl --silent http://buildhost.domain:port/cancelQuietDown
to resume the server
by http
There is no custom Java or Ruby or Python binding necessary to talk to the Jenkins server; no custom socket or networking code or proprietary protocols are needed. It is controlled entirely through the HTTP server that is already running and serving normal web traffic. My script could have been written in Java or Scala or Perl or any number of other scripting languages. Importantly, the Jenkins developers did not have to create custom Java, C#, C, Ruby, Python or other binding for controlling the server. By using REST, they open the system to any client and don't alienate any developer community.
What I like is the uniformity: if you find information on a web page in Jenkins, it is trivial to find the API to fetch that information: just append /api/xml or /api/json to the URL. The cost of entry is exceedingly low.
buy it, yet?
As we evolve our own development, build, test, and production pipelines, we could leverage such API's internally to great advantage. No screen scraping to determine what builds passed or failed or when builds are scheduled to run; no screen scraping to find what third party jars are available for each track and what their versions are, or what is scheduled in what ship events.
All the metadata about the builds, pipeline, etc. could be exposed via RESTful APIs and tools and apps could consume them in myriad ways.
Ah, bliss.