I am trying to use HTTP Builder to make a POST request in a pipeline script, (do have it in a shared lib where it works via the command line) but need it to work in Jenkins
I am getting the following error when running in Jenkins.
No suitable ClassLoader found for grab
My script looks as follows
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7')
import static groovyx.net.http.ContentType.JSON
import static groovyx.net.http.Method.POST
import groovyx.net.http.HTTPBuilder
def gitUpdateStatus() {
String targetUrl = 'https://api.github.com/repos/myOrg/'
def http = new HTTPBuilder(targetUrl)
http.request(POST) {
uri.path = "myRepo/statuses/commit_id_here"
requestContentType = JSON
body = [state: 'failure', description: 'Jenkins Unit Tests', target_url: 'http://test.co.uk', context: 'unit tests']
headers.'Authorization' = "token 123"
headers.'User-Agent' = 'Jenkins Status Update'
headers.Accept = 'application/json'
response.success = { resp, json ->
println "GitHub updated successfully! ${resp.status}"
}
response.failure = { resp, json ->
println "GitHub update Failure! ${resp.status} " + json.message
}
}
node {
stage('Echo Client JS')
git branch: 'master', credentialsId: '${JENKINS_CREDENTIALS_ID}', url: 'git#github.com:myOrg/myRepo.git'
gitUpdateStatus()
}
I have seen many posts where the same issue has arisen but I just cannot seem to figure out how this has been fixed, can anyone assist please ?
Thank You
You cannot use #Grab directly in pipelines. You need to move gitUpdateStatus() function into Jenkins shared library. See Using third party libraries.
Related
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
I want to upload a txt file to a website using a POST request with HTTPBuilder and multipart/form-data
I've tried running my function and I get a HTTP 200 OK response, but the file doesn't appear on the website anywhere.
private Map fileUpload(String url, File file){
log.debug "doPost: $url body: ${file.getName()}"
FileBody fileBody = new FileBody(file,ContentType.APPLICATION_OCTET_STREAM)
def result = [:]
try {
def authSite = new HTTPBuilder(url)
authSite.auth.basic(user, password)
authSite.request(POST) { req ->
headers.Accept = "application/json, text/javascript, */*; q=0.01"
req.params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
req.params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 60000)
def mpe = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
mpe.addPart("gxt",fileBody)
req.setEntity(mpe)
response.success = { resp, reader ->
result = reader
}
response.failure = { resp, reader ->
println "My response handler got response: ${resp.statusLine}"
}
}
}
catch (e) {
log.debug("Could not perform POST request on URL $url", e)
throw e
}
return result
}
From debugging this is the status recieved
3695 [main] DEBUG org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
3695 [main] DEBUG org.apache.http.wire - << "Date: Thu, 10 Jan 2019 07:34:06 GMT[\r][\n]"
Anything I'm doing wrong? I don't get any errors but it just seems like nothing happens.
I don't have anything conclusive, but I suspect there is something invalid with the way you set up the multipart upload.
To help figure this out, below is a standalone, working, multipart upload groovy script using HttpBuilder:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
#Grab('org.apache.httpcomponents:httpmime:4.2.1')
import org.apache.http.entity.mime.content.*
import org.apache.http.entity.mime.*
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.POST
fileUpload('https://httpbin.org/post', new File('data.txt'))
Map fileUpload(String url, File file){
println "doPost: $url body: ${file.name}"
def result
try {
new HTTPBuilder(url).request(POST) { req ->
requestContentType = "multipart/form-data"
def content = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
content.addPart(file.name, new InputStreamBody(file.newInputStream(), file.name))
req.entity = content
// json might be something else (like a reader)
// depending on the response content type
response.success = { resp, json ->
result = json
println "RESP: ${resp.statusLine}, RESULT: $json"
}
response.failure = { resp, json ->
println "My response handler got response: ${resp.statusLine}"
}
}
} catch (e) {
println "Could not perform POST request on URL $url"
throw e
}
result
}
The script assumes a file data.txt with the data to post in the current directory. The script posts to httpbin.org as a working test endpoint, adjust accordingly to post to your endpoint instead.
Saving the above in test.groovy and executing will yield something like:
~> groovy test.groovy
doPost: https://httpbin.org/post body: data.txt
RESP: HTTP/1.1 200 OK, RESULT: [args:[:], data:, files:[data.txt:{ "foo": "bar" }], form:[:], headers:[Accept:*/*, Connection:close, Content-Type:multipart/form-data; boundary=ZVZuV5HAdPOt2Sv7ZjxuUHjd8sDAzCz9VkTqpJYP, Host:httpbin.org, Transfer-Encoding:chunked], json:null, origin:80.252.172.140, url:https://httpbin.org/post]
(note that first run will take a while as groovy grapes need to download the http-builder dependency tree)
perhaps starting with this working example and working your way back to your code would help you pinpoint whatever is not working in your code.
None of the lines after making httpRequest are getting executed. Everything else works fine in this function. What could be going wrong here?
However, network request is going fine and I am able to see the response in the console. httpRequest is being made via plugin
I've even tried CURL - but lines after curl are not executed.
#NonCPS
def doPRCommentBasedTesting() {
def causes = currentBuild.rawBuild.getCauses()
def commentURL
for(cause in causes) {
if (cause.class.toString().contains("GitHubPullRequestCommentCause")) {
commentURL = cause.getCommentUrl()
commentURL = commentURL.substring(commentURL.lastIndexOf("-") + 1)
println "This job was caused by job " + commentURL
def url1 = "https://<git_url>/api/v3/repos/<owner>/<repo>/issues/comments/" + commentURL
def commentText = httpRequest authentication: '<auth_cred>', url: url1, consoleLogResponseBody: true
println commentText
println commentText.getClass()
println "hello world, how are you doing today?"
}
else {
println "Root cause : " + cause.toString()
}
}
println "==============================="
return 0
}
A non cps function does not have the ability to pause in between because it runs in a go. You need to put network call into a different function that is not marked as nonCPS and then it will work. In general the nonCPS block should be very small and limited to code that cannot be serialised
I'm trying to test my Grails web application by creating and sending a multipart request from a stand-alone groovy test script that's built by gradle. But I'm struggling.
I can't attach a custom Content-ID header
I can't attach a file of random bytes created at runtime (I can attach an existing file, but I need many random files of varying size)
EDIT (Thanks to Xeon):
My script is now sending a valid multipart request, but my grails web app is not accepting any headers other than "Content-Type" for some reason.
Heres my code:
The Stand-Alone Test Script code:
void sendMultipartRequest(String url) {
HTTPBuilder httpBuilder = new HTTPBuilder(url)
httpBuilder.request(Method.POST){ req ->
MultipartEntityBuilder entityBuilder = new MultipartEntityBuilder()
entityBuilder.setBoundary("----boundary")
entityBuilder.setMode(HttpMultipartMode.RFC6532)
String randomString = myGenerateRandomStringMethod()
FormBodyPart formBodyPart = new FormBodyPart(
"SOME_NAME",
new InputStreamBody(new ByteArrayInputStream(randomString.bytes), "attachment", "SOME_NAME")
)
formBodyPart.addField("Content-ID", "abc123")
entityBuilder.addPart(formBodyPart)
response.success = { resp ->
println("Success with response ${resp.toString()}")
}
response.failure = { resp ->
println("Failure with response ${resp.toString()}")
}
delegate.setHeaders(["Content-Type":"multipart/related; boundary=----boundary"])
req.setEntity(entityBuilder.build())
}
}
Grails web-app side in the controller for handling posts:
def submitFiles() {
if(request instanceof MultipartHttpServletRequest){
HashMap<String, Byte[]> fileMap = extractMultipartFiles(request)
someService.doStuffWith(fileMap)
}
}
private HashMap<String, Byte[]> extractMultipartFiles(MultipartHttpServletRequest multipartRequest) {
HashMap<String, Byte[]> files = new HashMap<>()
for(element in mulipartRequest.multiFileMap){
MultipartFile file = element.value.first()
String contentId = multipartRequest.getMultipartHeaders(element.key).get("Content-ID")?.first()
if(contentId) files.put(contentId, file.getBytes())
}
return files
}
Libraries I'm using:
ext {
groovyVersion = "2.3.4"
commonsLangVersion = "2.6"
httpBuilderVersion = "0.7.1"
httpmimeVersion = "4.3.4"
junitVersion = "4.11"
}
dependencies {
compile "org.codehaus.groovy:groovy-all:${groovyVersion}"
compile "commons-lang:commons-lang:${commonsLangVersion}"
compile "org.codehaus.groovy.modules.http-builder:http-builder:${httpBuilderVersion}"
compile "org.apache.httpcomponents:httpmime:${httpmimeVersion}"
testCompile group: 'junit', name: 'junit', version: "${junitVersion}"
}
You can always use some subclass of ContentBody interface:
FormBodyPart(String name, ContentBody body)
For example use: InputStreamBody:
new FormBodyPart("name", new InputStreamBody(new RandomInputStream(...)), ContentType.MULTIPART_FORM_DATA);
You can use: RandomInputStream class.
And with headers you could probably use: HTTPBuilder$RequestConfigDelegate.setHeaders(Map headers) because it's set to delegate of inner closure.
I've used curl in the past to do this testing:
curl -v -F "param1=1" -F "param2=99" -F "fileparam=#somefile.flv;type=video/x-flv" http://localhost:8080/someapp/sessions
somefile.flv is in the current directory
Hi I am having a bit of trouble figuring out how I can access this web service: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL
Using the groovy Wslite library, seems to work fine with the depreciated Groovy Soap library but I am not allowed to use that.
The libraries are described here:
Groovy Soap Use
Groovy-Wslite
I am totally new to groovy and these technologies in general so forgive my ignorance.
Basically I want this code:
import groovy.swing.SwingBuilder
import groovy.net.soap.SoapClient
proxy = new SoapClient("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL")
def currency = ['USD', 'EUR', 'CAD', 'GBP', 'AUD']
def rate = 0.0
swing = new SwingBuilder()
refresh = swing.action(
name:'Refresh',
closure:this.&refreshText,
mnemonic:'R'
)
frame = swing.frame(title:'Currency Demo') {
panel {
label 'Currency rate from '
comboBox(id:'from', items:currency)
label ' to '
comboBox(id:'to', items:currency)
label ' is '
textField(id:'currency', columns:10, rate.toString())
button(text:'Go !', action:refresh)
}
}
frame.pack()
frame.show()
def refreshText(event) {
rate = proxy.ConversionRate(swing.from.getSelectedItem(), swing.to.getSelectedItem())
swing.currency.text = rate
}
Converted to work with the groovy-wslite library and I cant get it to work no matter what I do.
Here is the Wslite library again.
wslite library
Any help is greatly appreciated.
I find it helpful to use a tool like soapUI first to figure out what request a service is expecting. From there it's a matter of using the markup builder to build that request. The following should work from the groovyConsole:
#Grab(group='com.github.groovy-wslite', module='groovy-wslite', version='0.8.0')
import wslite.soap.*
def client = new SOAPClient('http://www.webservicex.net/CurrencyConvertor.asmx')
def response = client.send(SOAPAction: 'http://www.webserviceX.NET/ConversionRate') {
body {
ConversionRate( xmlns: 'http://www.webserviceX.NET/') {
FromCurrency('GBP')
ToCurrency('USD')
}
}
}
assert response
assert 200 == response.httpResponse.statusCode
println response.ConversionRateResponse.ConversionRateResult.text()