Not able to construct proper header for groovy function Get request - jenkins

Writing my first function here for Groovy native lib and running into an issue. A method to get Github Labels for pull-requests. #param github_token String token with permission to access and read PR information.
getLabelsPerPullRequest.groovy: 19: expecting '}', found ':' # line 19, column 28. 'Authorization': 'token '+ github_token, ^
Here is my function
import groovy.json.JsonSlurper
def getLabelsPerPullRequest(String github_token) {
def labels
def scmHead = jenkins.scm.api.SCMHead.HeadByItem.findHead(currentBuild.rawBuild.getParent())
def repo = scmHead.getSourceRepo()
def prId = scmHead.getId()
if(github_token && github_token != null) {
// Set the call headers with Oauth token.
def headers = "{'Authorization': 'token '+ ${github_token},'Accept': 'application/vnd.github.v3+json'}"
// Construct request number URL in Github
def pr_url = "https://github.optum.com/api/v3/repos/SOP-Bot/${repo}/pulls/${prNbr}"
def json = sh(
script: "curl -X Get ${pr_url} -H ${headers}",
returnStdout: true
)
def prInfo = JsonOutput.toJson(text: json)
labels = prInfo.labels
}
return labels
}

Each header needs to be a separate -H argument. You can do something like this. I added -s to curl because you probably don't want the extra progress output but it may not actually be an issue.
def headers = [
"-H 'Authorization: token ${gitub_token}'",
"-H 'Accept: application/vnd.github.v3+json'"
]
...
def json = sh(
script: "curl -s -X GET ${headers.join(' ')} '${pr_url}'",
returnStdout: true
)

Related

Save curl response in a variable in Jenkins declarative pipeline

I have a Jenkins decalarative pipeline where I am calling some URL via cURL which is returning JSON response. How to catch that JSON in a variable?
Have tried the below code but it's returning entire thing with path and command along with the response
environment {
token = bat(returnStdout: true, script: 'curl https://anypoint.mulesoft.com/accounts/login -H "Content-Type: application/json" -d "{\\"username\\" : \\"user\\",\\"password\\" : \\"pwd\\"}"').trim()
}
JSON response
C:\ProgramData\Jenkins\.jenkins\workspace\publish-api>curl https://anypoint.mulesoft.com/accounts/login -H "Content-Type: application/json" -d "{\"username\" : \"ap-1\",\"password\" : \"Ap5\"}"
{
"access_token": "axxxx-5ca2-48eb-9eb3-173c44a811",
"token_type": "bearer",
"redirectUrl": "/home/"
}
You can use the readJson method to get to your wished result. You don't necesseraly have to call it in your environment-block.
stage('Curl') {
steps {
script {
def cUrlResponse = bat(returnStdout: true, script: '#curl https://anypoint.mulesoft.com/accounts/login -H "Content-Type: application/json" -d "{\\"${env.username}\\" : \\"user\\",\\"${env.password}\\" : \\"pwd\\"}"').trim()
def responseJson = readJSON text: cUrlResponse
def accessToken = responseJson.access_token
def tokenType = responseJson.token_type
// do other stuff with the variables
}
}
}
To exclude the curl command from the output, add # in front of the script as stated in the documentation.

Jenkins pipeline: passing in data variable as string into curl command

So I'm trying to pass in a string (data) into this sendSlackMessage function but it's not going into the curl command correctly. data is being passed in from my jenkinsfile.
It's working fine in the echo command though.
Can someone tell me what I'm doing wrong?
data = """{'channel': '#mychannel','username': 'jenkins-bot','icon_emoji': ':lol:','text': 'HERERERERE (<$BUILD_URL|Open>)','attachments': [['color': '#36a64f','fields': ['title': 'UPDATING INFOR','value': 'HELLOWORLD','short': 'true']]]}"""
void sendSlackMessage(String data) {
this.steps.sh(returnStdout: true, script: "echo hello world ${data} hello world again")
this.steps.sh(returnStdout: true, script: "curl -X POST -H 'Content-type: application/json' --data '${data}' https://hooks.slack.com/services/T12345671/sdfsdfsdf/sdf7sdf7gsdf")
}
Please try the below implementation
data = """{'channel': '#mychannel','username': 'jenkins-bot','icon_emoji': ':lol:','text': 'HERERERERE (<$BUILD_URL|Open>)','attachments': [['color': '#36a64f','fields': ['title': 'UPDATING INFOR','value': 'HELLOWORLD','short': 'true']]]}"""
void sendSlackMessage(String data) {
List curlCommand = []
curlCommand.add('curl -X POST -H')
curlCommand.add('\'Content-type: application/json\'')
curlCommand.add('--data')
curlCommand.add(data) // Maybe you have to see if you see to add a single quote here and escape it
curlCommand.add('https://hooks.slack.com/services/T12345671')
sh (
returnStdout: true,
script: curlCommand.join(" "),
label: "send slack message"
)
}

How to use `StaplerResponse rsp` in `AsyncResourceDisposer.doStopTracking()`

I'm trying to remove (stop tracking) trackig item from Jenkins AsyncResourceDisposer (${JENKINS_URL}/administrativeMonitor/AsyncResourceDisposer) via groovy scripts (${JENKINS_URL}/script).
According to the Javadoc and source code
// Javadoc
#Restricted(value=org.kohsuke.accmod.restrictions.DoNotUse.class)
public org.kohsuke.stapler.HttpResponse doStopTracking(#QueryParameter
int id,
org.kohsuke.stapler.StaplerResponse rsp
)
// source code
#Restricted(DoNotUse.class)
#RequirePOST
public HttpResponse doStopTracking(#QueryParameter int id, StaplerResponse rsp) {
...
}
I'd like to know how to add org.kohsuke.stapler.StaplerResponse rsp in doStopTracking(int id, org.kohsuke.stapler.StaplerResponse rsp):
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
disposer.backlog.each {
disposer.doStopTracking( it.id, <what should I put here> )
}
Current I can get the item id, and the other informaitons like below:
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
String url = Jenkins.instance.rootUrl + disposer.url
disposer.getBacklog().each { item ->
println "\n${item.id} : \t${url}/stopTracking/?id=${item.id} : \t${item.class.simpleName} : \n" +
"\t${item.getLastState().getDisplayName()} : \n" +
"\t${item.getDisposable().node} : ${item.getDisposable().path}\n" +
"\t${item.toString()}"
}
If I'm go to the url "${url}/stopTracking/?id=${item.id}" in browser (login first), the item can be removed after click RETRY USING POST (as below)
So... I'm using the API call curl -H <crumbIssues> -X POST <url> by passed the disposer.doStopTracking(int, org.kohsuke.stapler.StaplerResponse) (still really wants know how to use it)
Before running the following script, Strict Crumb Issuers Plugin is necessary to be installed and configured (or setup -Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true) due to SECURITY-626 : Improved CSRF protection since:
obtain a crumb using the /crumbIssuer/api URL will now fail to perform actions protected from CSRF unless the scripts retain the web session ID in subsequent requests.
Here is details:
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
import org.jenkinsci.plugins.strictcrumbissuer.StrictCrumbIssuer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
StrictCrumbIssuer issuer = jenkins.model.Jenkins.instance.crumbIssuer
String jenkinsCrumb = "${issuer.crumbRequestField}:${issuer.crumb}"
String url = Jenkins.instance.rootUrl + disposer.url
disposer.getBacklog().each { item ->
println "\n ~~> removeing ${item.id} : "
[ 'bash', '-c', 'curl -s ' +
'-u <user>:<token> ' +
'-X POST ' +
"-H \"Content-Type: application/json\" " +
"-H \"Accept: application/json\" " +
"-H \"${jenkinsCrumb}\" " +
"${url}/stopTracking/?id=${item.id} "
].execute().with{
def stdout = new StringBuffer()
def stderr = new StringBuffer()
it.waitForProcessOutput( stdout, stderr )
println "EXIT CODE: ${it.exitValue()}"
println "ERROR: ${stderr}"
println "OUTPUT: ${stdout}"
}
}
Although, I still have a question... As we know that if the groovy script running in ${JENKINS_URL}/script, which means the "runner" is the administrator, so, how I can remove the specific user authorication '-u <user>:<token>' (by using the jenkins administrator authorication) in curl ?

HTTP NTLM authentication in jenkins pipeline script

I am trying to post request which requires NTLM authentication. The curl command works fine when i do post call but same method request won't work with jenkins pipeline script.
Curl command:
curl -X POST -k -v -H \"Content-Type: application/json\" -H \"Content-Length: 0\" --ntlm -u domain/username:password http://blrapi/ExeWebAPI/testplans/run/username/89cd1093-6558-4321-b689-cb1
Jenkins Pipeline code
def getClient(){
def server = ""
def username = "username"
def userpassword = "password"
def domain = "domain"
def client = new HttpClient()
client.state.setCredentials(
AuthScope.ANY,
new NTCredentials(username, password, "", domain)
)
return client
}
def RunPlan( planId ){
SknetPost("hhttp://blrapi/ExeWebAPI/testplans/run/username/89cd1093-6558-4321-b689-cb1","")
}
def skynetExecute(httpMethod){
def httpResponse = ""
def sknetClient = getClient()
try {
int result = sknetClient.executeMethod(httpMethod)
println "Return code: ${result}"
httpResponse = httpMethod.getResponseBodyAsString()
}
finally {
httpMethod.releaseConnection()
}
return httpResponse
}
void SknetPost(url, jsondata) {
def post = new PostMethod( url )
post.doAuthentication = true
post.setRequestHeader("Content-type", "application/json")
StringRequestEntity requestEntity = new StringRequestEntity( jsonData , "text/html", "UTF-8");
post.setRequestEntity(requestEntity);
httpResponse = sknetExecute(post)
return httpResponse
}
}
When i execute the program it gives 401- unauthorized access error. Same credentials were used curl command it works fine but in jenkins pipeline it fails.
Please help me to solve this issue.
Web requests with NTLM authentication from Jenkins pipeline could be realized with the HTTP Request Plugin.
Add the Credential (user/password) in the jenkins credential store.
You could then use httpRequest in your pipeline:
script {
def response = httpRequest httpMode: 'GET',
url: "http://localhost:80",
authentication: '3bb9use-your-id-from-store',
useNtlm: true
println("Status: "+response.status)
println("Content: "+response.content)
}
Regards.
work for me with jenkins 2.324, HTTP Request Plugin 1.12

Executing CURL in Shared Library Jenkins Pipeline Using `Process`

I have a method in a shared library in my Jenkins pipeline. The idea is to use this library and upload files to a remote host. The library is imported in a singleton library.
import com.package.jobutil.UploadFile
def uploadFunc() {
def uploader = new UploadFile(this)
withCredentials ([usernamePassword(credentialsId: 'user', userNameVariable: 'username', passwordVariable:'password)]) {
uploader.uploadArtifact("${username}", "${password}", file.txt, location)
}
}
def call() {
uploadFunc()
}
The class that is instantiated looks like this:
class UploadFile {
def steps
UploadFile (steps) {
this.steps = steps
}
pulic uploadArtifct (String user, String password, String file, String location) {
Process proc
def cred = "${user}:${pass}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", file, location]
steps.println "CURL: ${cmd}"
proc = cmd.execute()
}
}
Even though I see the println line in the logs. I do not see the curl command being executed.
Is there something I am missing that does not invoke the cmd.execute to work?
EDIT
When I use the curl directly in the library, it works.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = "curl -v -u ${cred} --upload-file ${file} ${nexusLocation}/${file}"
try {
steps.sh cmd
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
However, when trying to use the Process it does not work.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}]
try {
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
The exception I get is:
java.lang.RuntimeException: Cannot execute curl, exception: [groovy.lang.MissingMethodException - 'No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
As explained here, you need to capture stdout/stderr to see anything.
At the very least:
def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
Or, as in this gist:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
An example of blocking call would be:
println new ProcessBuilder( 'sh', '-c', 'du -h --max-depth=1 /var/foo/bar/folder\\ with\\ spaces | sort -hr').redirectErrorStream(true).start().text
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}/${file}]
No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
The '/' in '${location}/${file}' is interpreted as an '/ (div) operation instead of a string.
Try instead for that curl command argument:
${location}+"/"+${file}
As noted in your subsequent question, the all path needs to be between double-quotes.

Resources