dockeransiblejenkins-pipelinejenkins-docker

docker.image...inside with dir and ansiblePlaybook results in java.lang.ArrayIndexOutOfBoundsException


Problem

If I combine docker.image...inside with dir and ansiblePlaybook I get an java.lang.ArrayIndexOutOfBoundsException and since my jenkins agent isn't using -XX:-OmitStackTraceInFastThrow that is all I get.

Any ideas as to why this is a problem and how I can resolve it without reworking all my dir calls?

Environment

Error

java.lang.ArrayIndexOutOfBoundsException

Failing Code

docker.withRegistry("https://myregistry", 'credsId') {
    docker.image("myregistry/jenkins-node-devops-tools:2020-07-17").inside {
        dir('backend') {
            ansiblePlaybook(
                    playbook: 'deploy/kafka-topics/test.yml',
                    extras: '-vv'
            )
        }
    }
}

Successful code

docker.withRegistry("https://myregistry", 'credsId') {
    docker.image("myregistry/jenkins-node-devops-tools:2020-07-17").inside {
            ansiblePlaybook(
                    playbook: 'backend/deploy/kafka-topics/test.yml',
                    extras: '-vv'
            )
    }
}

Additionally Successful code

dir('backend') {
    ansiblePlaybook(
            playbook: 'deploy/kafka-topics/test.yml',
            extras: '-vv'
    )
}

Solution

  • The docker command line and the environment are the context differences. Get them and check them first. Jenkins credential plugins will shield some environment variable, so you might need to direct them into a local file to by pass sh "env > file.txt"

    note: only use this rare debugging situations and clean it thoroughly afterwards as this is a way for secrets to leak out.

    The problem is more complex because it didn't just involve this code, but some code I left out. Here's the root cause

    I had a withArtifactoryEnvAuth function that allowed builds do to the following:

    withArtifactoryEnvAuth('mycreds') {
        sh 'docker pull image'
    }
    

    This code used the following. Now, when we use withCredentials it injects the cred values into the environment (maybe it always did, maybe that changed since I wrote this - it is probably the former). So, this code sets environment variables twice violating the DRY principle and it overwrites the USER variable which matters greatly on linux.

    Failing Code

    def withArtifactoryEnvAuth(def credentialsId, closure) {
    
        def message = ""
        withCredentials([usernamePassword(
                credentialsId: credentialsId, passwordVariable: 'PASSWORD', usernameVariable: 'USER')]) {
            List envList = [
                    "ARTIFACTORY_USER=${env.USER}",
                    "ARTIFACTORY_PASSWORD=${env.PASSWORD}"
            ]
            withEnv(envList) {
                message = closure()
            }
        }
    
        return message
    }
    

    Fixed Code

    def withArtifactoryEnvAuth(def credentialsId, closure) {
    
        def message = ""
        withCredentials([usernamePassword(
                credentialsId: credentialsId, passwordVariable: 'ARTIFACTORY_PASSWORD', usernameVariable: 'ARTIFACTORY_USER')]) {
            message = closure()
        }
    
        return message
    }