3

There's plenty of questions asking how to return a list of all jobs on your Jenkins instance, or even to get a list of which jobs are currently running, but I have a more specific use-case.

I need to see if a single job is already running. As in, return one value if there is 1 builds of the job running, and a different value if 2 or more builds are running.

The use case here is that we've automated our image creation to build after successful unit tests. It's set to build a maximum of one image every seven hours, by checking the build time of the last image and cancelling the build if it's been less than 7hrs. This works perfectly for most cases. However, these images take ~20min to build. If it's been over 7 hours and two unit tests finish within less than 20min of each other, the second build doesn't see the first creating, and continues building. We're getting two functionally identical images made once every 7hrs, only minutes apart. I'd like to check the status of the controller job to know if it's already running, so that the second build can know to cancel.

I've tried curl-ing the following API, but it turns out it doesn't register individual builds, just that the job is running in general, which is useless in this case as it self-triggers since it checking means it's already running; there's no difference between a single build and multiple builds.

http://JENKINS_URL/api/xml?tree=jobs[name,url,color]&xpath=/hudson/job[ends-with(color/text(),%22_anime%22)]&wrapper=jobs

TL;DR: Is there a different call I can make that will return some list/file/content that indicates that multiple builds of the same job are currently running?

2 Answers 2

8

Turns out you can hit the following URL to get an XML output of all currently running builds, including their build numbers.

http://jenkinsURL/computer/api/xml?tree=computer[executors[currentExecutable[url]],oneOffExecutors[currentExecutable[url]]]&xpath=//url&wrapper=builds

I greped it for a count and used that for my calculations.

0

I used the Groovy script console to obtain it this way:

def executables = Jenkins.instance.computers.collect {c -> c.executors}.
def runs = Jenkins.instance.computers.collect {c -> c.executors}.
   flatten().
  findAll { executor -> executor.isBusy() }.
  collect { executor -> executor.getCurrentExecutable() }.
    collect { executable -> "${executable.displayName}: ${executable.number}" }

or if you want the Build class, this:

Jenkins.instance.computers.collect {c -> c.executors}.
  flatten().
  findAll { executor -> executor.isBusy() }.
  collect { executor ->
    def u = executor.currentExecutable.url
    def n = executor.currentExecutable.number
    def job_qual_name = u.split('/')[0..-2].findAll { it != 'job' }.join('/')
    def job = Jenkins.instance.getItemByFullName(job_qual_name, Job.class)
    job.getBuildByNumber(build.number)
  }

It's pretty painful that Jenkins doesn't provide something as simple as this with a clear, high-level API.

It's extra ugly that the paths used by the folders plugin jobs don't work with Jenkins.getItemByFullName() without munging. Ick. Also that Jenkins.getItemByFullName() doesn't seem to support getting a Build.

You won't want to put this in Pipeline code. Instead put it in your script library so it isn't subject to method authorization issues, and only returns the final results.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.