Search code examples
jenkinspluginsgroovyremoteapi

Install Jenkins plugins over remote API synchronously (wait until finished) OR find out when all plugins have been installed


I am aware of two approaches to installing Jenkins plugins over the remote API, given a textfile with a newline separated list of plugin shortNames, e.g.

# plugins.txt
ansicolor
bitbucket
cobertura

POSTing XML over the remote API using curl:

JENKINS_URL="http://my-jenkins:8080/"
JENKINS_CRUMB=$(curl -s "${JENKINS_URL}"'/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')

while read plugin; do
   echo "Installing ${plugin} ..."
   curl -X POST --data "<jenkins><install plugin='${plugin}@latest' /></jenkins>" -H "${JENKINS_CRUMB}" -H 'Content-Type: text/xml' "${JENKINS_URL}"/pluginManager/installNecessaryPlugins
done <"${PLUGINS_FILE}"

Alternatively, POST a Groovy script to the remote endpoint which will essentially do the same thing:

# install_plugins.groovy

import jenkins.model.*
import java.util.logging.Logger

def logger = Logger.getLogger("")
def installed = false
def initialized = false

def plugins = new File('plugins.txt') as String[]

def instance =Jenkins.getInstance()
def pm = instance.getPluginManager()
def uc =instance.getUpdateCenter()
uc.updateAllSites()

plugins.each {   logger.info("Checking ${it}")
if (!pm.getPlugin(it)) {
    logger.info("Looking UpdateCenter for ${it}")
    if (!initialized) {
      uc.updateAllSites()
      initialized = true
    }
    def plugin = uc.getPlugin(it)
    if (plugin) {
      logger.info("Installing ${it}")
        plugin.deploy()
      installed = true
    }   } }

if (installed)
   {
      logger.info("Plugins installed, initializing a   restart!")
       instance.save()
       instance.doSafeRestart()
 }

Shell:

export JENKINS_URL="http://my-jenkins:8080/"
export JENKINS_CRUMB=$(curl -s "${JENKINS_URL}"'/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
curl -H ${JENKINS_CRUMB} -d "script=$(cat install_plugins.groovy)" "${JENKINS_URL}/scriptText"

What both approaches have in common, however, is the fact that each request for installing a plugin is handled asynchronously by Jenkins and hence returns immediately. The plugins will then be installed in the background.

However, I would like to automatically trigger a Jenkins restart and notify the user that everything is ready to work once all plugins are installed. The only solution I am currently aware of is opening the Plugin manager UI in a browser and hit refresh until I have the impression that nothing is changing anymore, then manually trigger the restart.

Is there any way to either

  • install the plugins synchronously (one after one), waiting until it and its dependencies are fully installed before continuing with the next one (I wouldn't mind the longer runtime)

or, alternatively

  • kick off the asynchronous jobs but regularly query the server until all plugins and their dependencies have been installed?

Solution

  • You can GET this endpoint:

    http://my-jenkins:8080/updateCenter/api/json?tree=jobs[*]
    

    That will give you a response like this:

    {
       "_class":"hudson.model.UpdateCenter",
       "jobs":[
      {
         "_class":"hudson.model.UpdateCenter$ConnectionCheckJob",
         "errorMessage":null,
         "id":3,
         "type":"ConnectionCheckJob"
      },
      {
         "_class":"hudson.model.UpdateCenter$InstallationJob",
         "errorMessage":null,
         "id":1,
         "type":"InstallationJob",
         "name":"Xamarin Studio Tool Runner Plugin",
         "status":{
            "_class":"hudson.model.UpdateCenter$DownloadJob$SuccessButRequiresRestart"
         },
         "plugin":{
    
         }
      },
      {
         "_class":"hudson.model.UpdateCenter$InstallationJob",
         "errorMessage":null,
         "id":2,
         "type":"InstallationJob",
         "name":"PAM Authentication plugin",
         "status":{
            "_class":"hudson.model.UpdateCenter$DownloadJob$Pending"
         },
         "plugin":{
    
         }
      }
    ]}
    

    Then it's a case of waiting for all the jobs of class hudson.model.UpdateCenter$InstallationJob to have status hudson.model.UpdateCenter$DownloadJob$SuccessButRequiresRestart or hudson.model.UpdateCenter$DownloadJob$Success. It will also be worth looking for hudson.model.UpdateCenter$DownloadJob$Failure or hudson.model.UpdateCenter$DownloadJob$Skipped and handling appropriately.