Search code examples
githubjenkinsansiblejenkins-pipelineansible-inventory

Jenkins dynamic choice parameter to read a ansible host file in github


I have an ansible host file that is stored in GitHub and was wondering if there is a way to list out all the host in jenkins with choice parameters? Right now every time I update the host file in Github I would have to manually go into each Jenkins job and update the choice parameter manually. Thanks!


Solution

  • I'm assuming your host file has content something similar to below.

    [client-app]
    client-app-preprod-01.aws-xxxx
    client-app-preprod-02.aws
    client-app-preprod-03.aws
    client-app-preprod-04.aws
    
    [server-app]
    server-app-preprod-01.aws
    server-app-preprod-02.aws
    server-app-preprod-03.aws
    server-app-preprod-04.aws
    

    Option 01

    You can do something like the one below. Here you can first checkout the repo and then ask for the user input. I have implemented the function getHostList() to parse the host file to filter the host entries.

    pipeline {
        agent any
    
        stages {
            stage('Build') {
                steps {
                    git 'https://github.com/jglick/simple-maven-project-with-tests.git'
                    script {
                        def selectedHost = input message: 'Please select the host', ok: 'Next',
                                            parameters: [
                                            choice(name: 'PRODUCT', choices: getHostList("client-app","ansible/host/location"), description: 'Please select the host')]
                        
                        echo "Host:::: $selectedHost"
                    }
                }
            }
        }
    }
    
    def getHostList(def appName, def filePath) {
    
        def hosts = []
        def content = readFile(file: filePath)
        def startCollect = false
        for(def line : content.split('\n')) {
            if(line.contains("["+ appName +"]")){ // This is a starting point of host entries
                startCollect = true
                continue
            } else if(startCollect) {
                if(!line.allWhitespace && !line.contains('[')){
                    hosts.add(line.trim())
                } else {
                    break
                }
            } 
        }
        return hosts
    }
    

    Option 2

    If you want to do this without checking out the source and with Job Parameters. You can do something like the one below using the Active Choice Parameter plugin. If your repository is private, you need to figure out a way to generate an access token to access the Raw GitHub link.

    properties([
        parameters([
            [$class: 'ChoiceParameter', 
                choiceType: 'PT_SINGLE_SELECT', 
                description: 'Select the Host', 
                name: 'Host',
                script: [
                    $class: 'GroovyScript', 
                    fallbackScript: [
                        classpath: [], 
                        sandbox: false, 
                        script: 
                            'return [\'Could not get Host\']'
                    ], 
                    script: [
                        classpath: [], 
                        sandbox: false, 
                        script: 
                            '''
                            def appName = "client-app"
                            def content = new URL ("https://raw.githubusercontent.com/xxx/sample/main/testdir/hosts").getText()
                            def hosts = []
                            def startCollect = false
                            for(def line : content.split("\\n")) {
                                if(line.contains("["+ appName +"]")){ // This is a starting point of host entries
                                    startCollect = true
                                    continue
                                } else if(startCollect) {
                                    if(!line.allWhitespace && !line.contains("[")){
                                        hosts.add(line.trim())
                                    } else {
                                        break
                                    }
                                } 
                            }
                            return hosts
                            '''
                    ]
                ]
            ]
        ])
    ])
    pipeline {
        agent any
        stages {
            stage('Build') {
                steps {
                    script {
                        echo "Host:::: ${params.Host}"
                    }
                }
            }
        }
    }
    

    Update

    When you are calling a private repo, you need to send a Basic Auth header with the access token. So use the following groovy script instead.

    def accessToken = "ACCESS_TOKEN".bytes.encodeBase64().toString()
    def get = new URL("https://raw.githubusercontent.com/xxxx/something/hosts").openConnection();
    get.setRequestProperty("authorization", "Basic " + accessToken)
    def content = get.getInputStream().getText()