Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
588 views
in Technique[技术] by (71.8m points)

rest - Jenkinsfile/Groovy: Why does curl command result in "bad request"

I recently learned about withCredentials DSL thanks to an answer to this question. Having attempted to use @RamKamath's answer, i.e. the following Jenkinsfile:

pipeline {
agent any
stages {
stage( "1" ) {
  steps {
    script {
     def credId = "cred_id_stored_in_jenkins"
     withCredentials([usernamePassword(credentialsId: credId,
                                       passwordVariable: 'password',
                                       usernameVariable: 'username')]) {
      String url = "https://bitbucket.company.com/rest/build-status/1.0/commits"
      String commit = '0000000000000000000000000000000000000001'
      Map dict = [:]
      dict.state = "INPROGRESS"
      dict.key = "foo_002"
      dict.url = "http://server:8080/blue/organizations/jenkins/job/detail/job/002/pipeline"
      List command = []
      command.add("curl -f -L")
      command.add('-u ${username}:${password}')
      command.add("-H \"Content-Type: application/json\"")
      command.add("-X POST ${url}/${commit}")
      command.add("-d \''${JsonOutput.toJson(dict)}'\'")
                         
      sh(script: command.join(' '))
     }
    }
   }
  }
 }
}

...the curl command itself fails because of a reported "Bad request" error. This is the snippet from the Jenkins console output:

+ curl -f -L -u ****:**** -H "Content-Type:application/json" -X POST https://bitbucket.company.com/rest/build-status/1.0/commits/0000000000000000000000000000000000000001 -d '{"state":"INPROGRESS","key":"foo_002","url":"http://server:8080/blue/organizations/jenkins/job/detail/job/002/pipeline"}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100   153    0     0  100   153      0   4983 --:--:-- --:--:-- --:--:--  5100
curl: (22) The requested URL returned error: 400 Bad request

I understand that -u ****:**** is the masked username:password argument to -u.
If I copy/paste that exact string into a shell, and replace the masked values with the real values, the curl command works:

$ curl -f -L -u super_user:super_password -H "Content-Type:application/json" -X POST https://bitbucket.company.com/rest/build-status/1.0/commits/0000000000000000000000000000000000000001 -d '{"state":"INPROGRESS","key":"foo_002","url":"http://server:8080/blue/organizations/jenkins/job/detail/job/002/pipeline"}'
$ 

What is going wrong? Why does the curl command result in error 400/"Bad request" when Jenkins executes it, but the same command runs fine when executed manually?

Please note: as was recommended, I enclosed the -u ${username}:${password} in single-quotes, not double-quotes.


Update: I feel as though something is wrong with the string interpolation, because if I modify the Jenkinsfile to add a hardcoded username/password, i.e.

command.add('-u super_user:super_password')

...instead of

command.add('-u ${username}:${password}')

...then the curl command still fails exactly as before, i.e. because of the error: 400 Bad request

Can someone please help me identify what is wrong, presumably with the command assembly, and/or the sh() invocation?


Update

I've simplified the problem by removing the withCredentials(). Even this simplified curl invocation fails:

pipeline {
agent any
stages {
stage( "1" ) {
  steps {
    script {
     def credId = "cred_id_stored_in_jenkins"
     String url = "https://bitbucket.company.com/rest/build-status/1.0/commits"
     String commit = '0000000000000000000000000000000000000001'
     Map dict = [:]
     dict.state = "INPROGRESS"
     dict.key = "foo_002"
     dict.url = "http://server:8080/blue/organizations/jenkins/job/detail/job/002/pipeline"
     List command = []
     command.add("curl -f -L")
     command.add('-u super_user:super_password')
     command.add("-H \"Content-Type: application/json\"")
     command.add("-X POST ${url}/${commit}")
     command.add("-d \''${JsonOutput.toJson(dict)}'\'")

     sh(script: command.join(' '))
    }
   }
  }
 }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I tried it with an adaption of your script inline a Pipeline project:

pipeline {
    agent any
    stages {
        stage( "1" ) {
            steps {
                script {
                  def username = '********' // my real jenkins user
                  def password = '********' // my real jenkins pwd
                  String url = "http://localhost:8083/api/json"
                  String commit = ""
                  List command = []
                  command.add("'C:/Program Files/Git/mingw64/bin/curl.exe' -f -L")
                  command.add("-u ${username}:${password}")
                  command.add('-H "Content-Type: application/json"') // no "..." string delimiters and escaping necessary
                  //command.add("-X POST ${url}/${commit}")
                  command.add("-X GET ${url}/${commit}")  // GET instead
                  //command.add("-d \''${JsonOutput.toJson(dict)}'\'")
            
                  sh(script: command.join(' '))
                }
            }
        }
    }
}

Console Output

+ 'C:/Program Files/Git/mingw64/bin/curl.exe' -f -L -u ********:******** -H 'Content-Type: application/json' -X GET http://localhost:8083/api/json/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  3232  100  3232    0     0  42667      0 --:--:-- --:--:-- --:--:-- 43675{"_class":"hudson.model.Hudson","assignedLabels":[{"name":"master"}],"mode":"NORMAL","nodeDescription":"the master Jenkins node","nodeName":"","numExecutors":2,"description":null,"jobs":
...

And I remember Jenkinsfile idiosynchrasies with escaping and quotes.

With Credentials Binding Plugin

        stage( "curl withCredentials" ) {
            steps {
                script {
                    withCredentials([usernamePassword(
                            credentialsId: 'jenkins-user',
                            passwordVariable: 'password',
                            usernameVariable: 'username')]) {
                                
                      String url = "http://localhost:8083/api/json"
                      String commit = ""
                      List command = []
                      command.add("'C:/Program Files/Git/mingw64/bin/curl.exe' -f -L")
                      command.add("-u ${username}:${password}")
                      command.add('-H "Content-Type: application/json"') // no "..." string delimiter and escaping necessary
                      //command.add("-X POST ${url}/${commit}")
                      command.add("-X GET ${url}/${commit}")  // GET instead
                      //command.add("-d \''${JsonOutput.toJson(dict)}'\'")
    
                      sh(script: command.join(' '))
                    }
                }
            }
        }            

Console Output

+ 'C:/Program Files/Git/mingw64/bin/curl.exe' -f -L -u ****:**** -H 'Content-Type: application/json' -X GET http://localhost:8083/api/json/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  3231  100  3231    0     0  42247      0 --:--:-- --:--:-- --:--:-- 42513
100  3231  100  3231    0     0  42216      0 --:--:-- --:--:-- --:--:-- 42513{"_class":"hudson.model.Hudson","assignedLabels":[{"name":"master"}],"mode":"NORMAL","nodeDescription":"the master Jenkins node","nodeName":"","numExecutors":2,"description":null,"jobs":
...

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...