Jenkins — один из наиболее популярных инструментов CI/CD. Он позволяет автоматизировать каждый этап жизненного цикла программного обеспечения: от создания до развертывания. В этой статье Кирилл Борисов, Infrastructure Engineer технологического центра Deutsche Bank, расскажет о параметрах в Jenkins и о том, как решить проблему хардкода с их помощью.

Основные виды параметров

Чтобы добавить параметры в Job, необходимо установить галочку «This project is parameterised»:

 По умолчанию Jenkins предоставляет несколько типов параметров, но вы можете расширять это список, используя Plugins. Например, вы можете добавить Active Choice Parameter, о котором мы поговорим далее.

Вот основные параметры, которые Jenkins предлагает «из коробки»:

  1. Boolean Parameter определяет логические параметры. Может принимать значения true/false. Также для параметра можно задать значение по умолчанию.

    booleanParam (name: «DryRun», defaultValue: true, description: «Тестовый запуск»)

  2. String Parameter определяет одностроковый параметр. Поддерживает удаление пробелов с обоих сторон от введённого значения.

    string (name: «version», defaultValue: «r48», trim: false, description: «Введите версию компонента»)

  3. Multi-line String Parameter определят многостроковый параметр.

    text (name: «releaseNotes», defaultValue: «none», description: «Описание изменений в релизе»)

  4. Password позволяет определить ввод пароля. Данные пароля не будут отображаться при запуске Job и в console log.

    password (name: «password», defaultValue: «changeme», description: «Введите пароль»)

  5. Choice Parameter позволяет выбрать несколько параметров из списка ранее предустановленных параметров.
    choice (name: «env», choices: [«PROD», «DEV», «UAT»], description: «Выберите окружение для установки релиза»)

Как объявлять параметры в Jenkinsfile

pipeline {
    agent any
    parameters {
        booleanParam(name: "dryrun", defaultValue: true, description: "Тестовый запуск")
        string(name: "version", defaultValue: "r48", trim: true, description: "Введите версию компонента")
        text(name: "releaseNotes", defaultValue: "Добавлены новые feature", description: "Описание изменений в релизе")
        password(name: "password", defaultValue: "changeme", description: "Введите пароль")
        choice(name: "env", choices: ["PROD", "DEV", "UAT"], description: "Sample multi-choice parameter")
    }
    stages {
        stage('DryRun') {
            when {
                expression { params.dryrun }
            }
            steps {
                echo "THIS IS DRYRUN!"
            }
        }
        stage("Build") {
            steps {
                echo "Build stage."
                echo "Hello $params.version"
            }
        }
        stage("Test") {
            steps {
                echo "Test stage."
            }
        }
        stage("Release") {
            steps {
                echo "Defined release notes $params.releaseNotes"
                echo "Starting release on $params.env"
            }
        }
    }
}

При запуске Job в Jenkins мы увидим: 

И наконец то вывод нашего pipeline:

Active Choice Parameter

Active Choice Parameter не добавляется по умолчанию. Для его использования сначала нужно установить плагин Active Choices.

Как написано в документации: «Active Choices используется для параметризация Jenkins Job и для создания динамических и интерактивных параметров. Параметры Active Choices могут динамически обновляться и отображаться в виде полей со списком, флажков, переключателей или виджетов пользовательского интерфейса с HTML».

В нашем распоряжении появилось 3 дополнительных опции в разделе параметры:

Рассмотрим каждую из них:

  1. Active Choices Parameter позволяет использовать сценарий Groovy или Scriplet(плагин), чтобы определить, будет ли ввод вычисляться или он уже предопределен, и возвращать результаты в зависимости от выполненных скриптов.

  2. Active Choices Reactive Parameter похож на Active Choice Parameter. Он позволят использовать Groovy или Scriplet, а его значение меняется в зависимости от значения выбранного зависимого параметра.

  3. Active Choices Reactive Reference Parameter содержит параметры Active Choice Parameter и Active Choice Reactive Parameter, а также добавляет новые опции. Например, HTML-виджеты, маркированные или нумерованные списки и поля ввода.

Перейдём к практике: кейс использования Active Choice Parameter

Представим, что у вас есть задача сделать Job, который позволит разработке или L2 support устанавливать сервис определенной версии в нужное окружение. Кажется, всё должно быть автоматизировано, но на практике возникает ситуация, когда разработчик или QA-инженер хочет проверить свою версию микросервиса на определенном окружении. Это можно было бы сделать и с использованием обычных string-параметров, но давайте упростим задачу и предоставим более дружественный интерфейс.

Для начала добавим выбор компонентов, используя gitlab api, напишем простой groovy скрипт для получения списка проектов, а затем создадим Jenkinsfile и добавим в него определение нашего параметра:

properties([
    parameters([
        [$class: 'ChoiceParameter',
            choiceType: 'PT_SINGLE_SELECT',
            description: 'Select a choice',
            filterLength: 1,
            filterable: false,
            name: 'component',
            script: [$class: 'GroovyScript',
                fallbackScript: [classpath: [], sandbox: false, script: 'return ["Could not get component"]'],
                script: [classpath: [], sandbox: false, 
                    script: """
                         import groovy.json.JsonSlurperClassic
                            def list = []
                            def connection = new URL("https://run.mocky.io/v3/e406ee99-be79-4d50-818f-b186dad7f4f4")
                            .openConnection() as HttpURLConnection
                            connection.setRequestProperty('Accept', 'application/json')
                            def json = connection.inputStream.text
                            data = new JsonSlurperClassic().parseText(json)
                            data.each { component ->
                                list += component.name
                            }
                            return list
                    """
                ]]]])
])
pipeline {
    agent any

    stages {
        stage("Component Name") {
            steps {
                sh "echo Selected component  ${params.component}"
            }
        }
    }
}

Не забываем, что новые скрипты нужно подтверждать:

Теперь перейдем к созданию Active Choices Reactive Parameter. В зависимости от выбранного компонента нам будут показываться все версии компонента в артефатори.

Создадим простой groovy-скрипт и добавим описание в Jenkinsfile:

[$class: 'CascadeChoiceParameter', 
        choiceType: 'PT_SINGLE_SELECT', 
        description: 'Select Version', 
        filterLength: 1, 
        filterable: true, 
        name: 'version', 
        referencedParameters: 'component', 
        script: [
            $class: 'GroovyScript', 
            fallbackScript: [
                classpath: [], 
                sandbox: false, 
                script: 
                    'return[\'Could not get version\']'
            ], 
            script: [
                classpath: [], 
                sandbox: false, 
                script: 
                    """
                            import groovy.json.JsonSlurperClassic
                            def list = []
                            def connection = new URL("https://run.mocky.io/v3/c782ae33-98a2-4994-acc4-14c0b5cc7655")
                            .openConnection() as HttpURLConnection
                            connection.setRequestProperty('Accept', 'application/json')
                            def json = connection.inputStream.text
                            data = new JsonSlurperClassic().parseText(json)
                            data.data.each { it ->
                              if  (it.component == component ) {
                                	list += it.version
                              		}
                               }
                            return list
                            """
            ]
        ]
    ]

Важное изменение — это опция referencedParameters. В ней мы указываем параметр, от которого зависит выполнение скрипта. Запускаем нашу Job, выбираем компонент и версию и смотрим на результат:

https://gist.github.com/silabeer/2bb3baf37c7ee1dbed369e84d4b8d9d0

В результате мы получаем удобство в эксплуатации: конечному пользователю не нужно каждый раз руками «вбивать» имя компонента и искать версию в артефактори, нужно просто выбрать из списка.

Для тех, кто хочет в тонкости работы с Jenkins и получить скидку 10% на обучение

6 сентября у нас стартует курс по Jenkins, автором которого выступил Кирилл Борисов, Infrastructure Engineer технологического центра Deutsche Bank. В курсе будет много кейсов и примеров из практики спикера.

Вы научитесь:

  • автоматизировать процесс интеграции и поставки;

  • ускорять цикл разработки и внедрять полезные инструменты;

  • настраивать плагины и создавать пайплайны Jenkins as a code;

  • работать с Jenkins Shared Library.

Промокод «READER» даёт скидку 10% при покупке курса.

Ознакомиться с программой и записаться: https://slurm.club/3bGiJzB

Комментарии (2)


  1. kWatt
    08.08.2022 21:48
    +1


    Хорошая и нужная статья. Спасибо что описали пример с activeChoice.
    Сам столкнулся с похожей задачей и решал с помощью etcd и вот такого кода:
    Jenkinsfile:

    def readService(){
      res = httpRequest(
          url: "http://etcd:2379/v2/keys?dir=true",
          httpMode: 'GET',
          consoleLogResponseBody: 'false'
      )
    
      stdjson = readJSON text: res.content, returnPojo: true
    
      listStages = [] as Set
      listServices = []
    
      stdjson.node.nodes.each { nodes ->
        listStages.add(nodes.key.split(',')[0].split('\\/')[1])
        listServices.add(nodes.key.split(',')[0].split('\\/')[2])
      }
      
      return [listStages as List , listServices]
    
    }
    
    pipeline {
    
        agent any
    
        parameters {
          choice(name: 'param_stage',   choices: readService()[0] )
          choice(name: 'param_service', choices: readService()[1] )
        }
    ...


  1. TuktarovMarat
    11.08.2022 12:06

    Groovy вставки в декларативном пайплайне выглядят, конечно, ужасно))

    если интересны подобные не совсем стандартные сценарии, то я бы посоветовал посмотреть в сторону вот этой shared либы. В своё время я нашёл там очень много фишечек https://github.com/SAP/jenkins-library