Dynamic Parameters in Jenkins Jobs

Today, we will explore two different approaches to parameterizing Jenkins jobs. Utilizing the Active Choices plugin, we aim to address two common challenges:

  • Populating a Parameter with External Data: For instance, you might want to list the regions available for deploying EC2 instances in an AWS account.
  • Dynamically Updating Parameters Based on Other Selections: For example, you may wish to update the available AMIs according to the AWS region selected by a user.

Let’s set up a fresh Jenkins instance to demonstrate how we can accomplish these tasks.

Installing Active Choices plugin

Navigate to the Jenkins Dashboard, then go to ‘Manage Jenkins‘ > ‘Manage Plugins‘. In the ‘Available Plugins‘ tab, search for the ‘Active Choices Plugin‘ and proceed with the installation.

Create a Job with Active Choices

To create a new job, begin from the Jenkins Dashboard. Select ‘New Item‘ and choose ‘Pipeline‘ as the type. In the job’s configuration settings, tick the ‘This project is parameterized‘ checkbox. Then, add an ‘Active Choice Parameter‘. Assign it a relevant name (country in our case) and make sure to select the ‘Groovy Script‘ option.

Utilizing Groovy Script to Fetch External Data for an Active Choice Parameter

The ‘Groovy Script‘ option within an Active Choice Parameter enables you to write a script for fetching external data. This feature is versatile, allowing for various functionalities, such as leveraging credentials stored in the Credential Manager to make API calls.

As an illustration, let’s create a practical example: we’ll use a Groovy script to fetch a list of countries from an external API and display these as selectable options in the job parameter. We’ll name our first parameter ‘country’ (take note of this name as it will be the variable name used to reference it in other Active Choice Parameters). To populate it, the script will make a call to the ‘https://restcountries.com‘ REST API. Here’s how we can do it:

import groovy.json.JsonSlurper
import java.net.URL

def getCountryNames() {
    def url = new URL("https://restcountries.com/v3.1/all")
    def connection = url.openConnection()
    def countriesJson = connection.content.text
    def countries = new JsonSlurper().parseText(countriesJson)
    def countryNames = []

    countries.each { country ->
        countryNames.add(country.name.common)
    }

    return countryNames
}

def countryNames = getCountryNames()
countryNames.sort().each { countryName ->
    println countryName
}

Be sure to approve the script if required and then Save. If you want to check how it works, select ‘Build with parameters‘ and if the parameter fetches the data properly:

There’s nothing special about the Groovy script. We are importing the required libraries to make an API call and then we parse to output them as part of the parameter. Keep in mind that according to the documentation, the Groovy script for an Active Choice Parameter must return a java.util.List, an Array or a java.util.Map.

Updating a Parameter Based on the Choice of Another Parameter

Next, we’ll create a dynamic interaction between parameters. Specifically, we will establish a parameter called ‘capital’ that updates dynamically based on the selection made in the ‘country’ parameter. This means that whenever a user selects a different country, the ‘capital’ parameter will automatically update to reflect the capital city of the chosen country. For instance, if ‘Spain‘ is selected as the country, the ‘capital‘ parameter should automatically update to ‘Madrid‘.

To accomplish this, we will utilize an ‘Active Choices Reactive Parameter‘. Set the ‘Referenced parameters’ property to target the desired parameter, which in this case is ‘country’ (notice you can target more than one parameter). In this setup, the Groovy script will employ the same endpoint as before. However, it will now additionally check the selected country to retrieve the corresponding capital:

import groovy.json.JsonSlurper
import java.net.URL

def getCapital(countryName) {
    // Replace spaces with '%20'
    def encodedCountryName = countryName.replaceAll(' ', '%20')
    def url = new URL("https://restcountries.com/v3.1/name/${encodedCountryName}")
    def connection = url.openConnection()
    def countryJson = connection.content.text
    def countryData = new JsonSlurper().parseText(countryJson)

    return countryData[0]?.capital ? countryData[0].capital[0] : 'Capital not found'
}

def countryName = country.trim()
return getCapital(countryName).split('\n').toList()

To accommodate countries with spaces in their names, such as ‘Costa Rica’ or ‘United States’, we needed to modify the script slightly. These spaces should be replaced with “%20” in the API call, as that is the format expected by the API. Apart from this adjustment, the script remains straightforward and easy to implement.

Now, if you go and check, the parameter capital will be automatically updated if the country changes:

Considerations for Active Choice and Reactive Parameters

It’s important to note that for some cases, values for Active Choice Parameters may take a moment to populate. Similarly, Reactive Parameters may also exhibit a slight delay in updating when the referenced parameter changes. While the example we’ve discussed is relatively simple, these techniques can be applied to a wide range of more complex and powerful scenarios.

A notable feature of using Groovy scripts in Jenkins is the ability to access all credentials stored in the Credential Manager. These credentials can be strategically used to make calls to APIs or other services. This method is not just about accessibility; it plays a crucial role in sanitizing data before any operation is executed, thereby ensuring data integrity and bolstering security.

Another impressive functionality is the execution of code on agents linked to Jenkins. This capability is particularly useful for tasks that require additional computing resources or specific environments. Additionally, fetching data from external sources through this method significantly helps in sanitizing the code. It reduces the potential for errors in jobs, leading to more reliable and efficient operations.

| Theme: UPortfolio