Search code examples
sonarqubejenkins-pipeline

SonarQube waitForQualityGate() returning 401


I have a SonarQube server and a Jenkins server. The Jenkins server has the following plugins installed.

  • Quality Gates Plugin
  • Sonar Quality Gates Plugin
  • SonarQubeScanner

I have configured a webhook in the SonarQube UI with the following URL.

http://myjenkins.com:8083/sonarqube-webhook/

I have a Jenkins Pipeline file as below.

pipeline {
    /*
    * Run everything on an existing agent configured with a label 'windows'.
    * TODO : Once we have enough agents, distribute to get fastest feedback!
    */
    agent any
    /*
    agent {
        node {
            label 'windows'
        }
    }
    */
    /*
    * We are getting a lot of values from BitBucket notifier plugin.
    */
    parameters {
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_URL')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_VERSION')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_AUTHOR_SLUG')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_TO_SSH_CLONE_URL')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_FROM_BRANCH')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_TO_BRANCH')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_TO_REPO_NAME')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_ID')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_TITLE')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_ACTION')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_REVIEWERS_SLUG')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_AUTHOR_EMAIL')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_AUTHOR_DISPLAY_NAME')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_USER_EMAIL_ADDRESS')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_USER_DISPLAY_NAME')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_STATE')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_REVIEWERS_EMAIL')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_REVIEWERS_APPROVED_COUNT')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_FROM_BRANCH')
        string(defaultValue: '', description: '', name: 'PULL_REQUEST_TO_REPO_PROJECT_KEY')
    }

    /* Add timestamps to the console log. Discard old builds.
    options {
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }
    */
    /* Stages can be parallel or sequential */
    stages {
        stage('Source-Code-Management') {
            steps {
                git(url: 'ssh://mybitbucketserver.com:7999/dev/sitecore.git', branch: '${PULL_REQUEST_FROM_BRANCH}', credentialsId: 'root')
                powershell "git merge origin/${PULL_REQUEST_TO_BRANCH}"
            }
        }
        stage('Build and Analyze') {
            steps {
                script {
                    // Todo we should be using environment variables or properties for sonar scanner and not have hardcoded values
                    bat "\"${tool 'nuget-4.3.0'}\" restore src/Nemlig.sln -NoCache"
                    withSonarQubeEnv('Local') {
                        bat "\"${tool 'SonarScanner.MSBuild.exe'}\" begin /d:sonar.login=mytoken /k:TEST /n:Website /v: /d:sonar.host.url=${SONAR_URL} /d:sonar.cs.nunit.reportsPaths=${WORKSPACE}\\NUnitResult.xml /d:sonar.cs.opencover.reportsPaths=${WORKSPACE}\\OpenCoverResult.xml"
                        bat "\"${tool 'MSBuild-v15'}\" src/Nemlig.sln /p:Configuration=debug"
                        // Note that this shell can retrieve value with CRLF and NUNIT will puke. Must replace with spaces...
                        def dlls = powershell(returnStdout: true, script: '(ls -Recurse src\\*\\bin\\*.Test.dll | % FullName)')
                        dlls = dlls.replaceAll('\r\n', ' ')
                        mycmd = "OpenCover.Console.exe -register:path64 -target:\"nunit3-console.exe\" -returntargetcode -targetargs:\"$dlls --result=NUnitResult.xml\" -output:OpenCoverResult.xml"
                        powershell (returnStatus: true, script: "$mycmd")
                        bat "\"${tool 'SonarScanner.MSBuild.exe'}\" end /d:sonar.login=mytoken"
                    }
                }
            }
        }
        stage('SonarQube Quality Gate') {
            steps {
                script {
                    timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
                        def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
                        if (qg.status != 'OK') {
                            error "Pipeline aborted due to quality gate failure: ${qg.status}"
                        }
                    }
                }
            }
        }
        stage('Deploy Team Environment') {
            parallel {
                stage('Deploy Site') {
                    steps {
                        powershell 'Write-Output "Here we could do a deploy of the site"'
                    }
                }
                stage('Deploy Backend') {
                    steps {
                        powershell 'Write-Output "Here we could do a deploy of the backend and maybe database changes?"'
                    }
                }
            }
        }
        stage('Smoke') {
            parallel {
                stage('Chrome') {
                    steps {
                        powershell 'Write-Output "Execute Smoke on Chrome"'
                    }
                }
                stage('Firefox') {
                    steps {
                        powershell 'Write-Output "Execute Smoke on Firefox"'
                    }
                }
                stage('Safari') {
                    steps {
                        powershell 'Write-Output "Execute Smoke on Safari"'
                    }
                }
            }
        }
        stage('integrate') {
            steps {
                powershell 'Write-Output "Push merge if all is success!"'
            }
        }
        stage('Store Binary') {
            steps {
                powershell 'Write-Output "Put the tested binary in Artifactory. Maybe tag it with SHA and Build Number?"'
            }
        }
    }
    post {
        // Add the publish merge steps...
        // Add the notifiy Jira steps
        always {
            script {
                currentBuild.result = currentBuild.result ?: 'SUCCESS'
                notifyBitbucket()
            }
            nunit testResultsPattern: "NUnitResult.xml"
        }
    }
}

I execute the pipeline and the analysis is correctly processed and uploaded to the SonarQube server. However the waitForQualityGate always returns a 401.

Checking status of SonarQube task 'AWKwODGjKw9CRrvU3S27' on server 'Local'

Error 401 on http://mysonarserver.com:9000/api/ce/task?id=AWKwODGjKw9CRrvU3S27

I can see from the logs that the taskID that is generated during the analysis is the same.

ANALYSIS SUCCESSFUL, you can browse http://10.100.1.189:9000/dashboard/index/TEST
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://mysonarserver.com:9000/api/ce/task?id=AWKwODGjKw9CRrvU3S27
INFO: Task total time: 3:00.752 s

I spun up a local RequestBin server setup a new webhook for that and saw that it did receive the data from SonarQube.

{
    "serverUrl": "http://localhost:9000", "taskId": "AWKwODGjKw9CRrvU3S27", "status": "SUCCESS", "analysedAt":
    "2018-04-11T07:41:40+0000", "changedAt": "2018-04-11T07:41:40+0000", "project":
    { "key": "TEST", "name": "Website", "url": "http://localhost:9000/dashboard?id=TEST" }, "branch":
    { "name": "master", "type": "LONG", "isMain": true, "url": "http://localhost:9000/dashboard?id=TEST" },
    "qualityGate": {
    "name": "Website", "status": "OK", "conditions": [{
                                                          "metric": "new_reliability_rating", "operator":
                                                          "GREATER_THAN", "value": "3", "status": "OK", "onLeakPeriod":
                                                          true, "errorThreshold": "3"
                                                      }, {
                                                          "metric": "new_duplicated_lines_density", "operator":
                                                          "GREATER_THAN", "status": "NO_VALUE", "onLeakPeriod": true,
                                                          "errorThreshold": "3"
                                                      }, {
                                                          "metric": "new_security_rating", "operator": "GREATER_THAN",
                                                          "value": "4", "status": "OK", "onLeakPeriod": true,
                                                          "errorThreshold": "4"
                                                      }, {
                                                          "metric": "blocker_violations", "operator": "GREATER_THAN",
                                                          "value": "-2", "status": "OK", "onLeakPeriod": true,
                                                          "errorThreshold": "35"
                                                      }, {
                                                          "metric": "new_maintainability_rating", "operator":
                                                          "GREATER_THAN", "value": "1", "status": "OK", "onLeakPeriod":
                                                          true, "errorThreshold": "1"
                                                      }]
}, "properties": {}
}

So I have no idea where to go now?

Any help would be appreciated!


Solution

  • The waitForQualityGate() step needs some credentials to fetch quality gate details from the SQ server. The credentials are expected to be set in Jenkins global configuration, for your 'Local' server.

    But according to your pipeline snippet, I see that you are passing manually /d:sonar.login=mytoken to the scanner. This is not supported. Please set the token in the global server configuration.