blob: a7e0f9756806175d830c5754d9299f80ca9f6fd2 [file] [log] [blame]
Jakub Josef79ecec32017-02-17 14:36:28 +01001package com.mirantis.mk
2/**
3 *
4 * HTTP functions
5 *
6 */
7
8/**
9 * Make generic HTTP call and return parsed JSON
10 *
11 * @param url URL to make the request against
12 * @param method HTTP method to use (default GET)
13 * @param data JSON data to POST or PUT
14 * @param headers Map of additional request headers
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030015 * @param read_timeout http session read timeout
Jakub Josef79ecec32017-02-17 14:36:28 +010016 */
Jakub Josefdb779dd2017-04-24 12:58:33 +020017@NonCPS
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030018def sendHttpRequest(url, method = 'GET', data = null, headers = [:], read_timeout=-1) {
Jakub Josef79ecec32017-02-17 14:36:28 +010019 def connection = new URL(url).openConnection()
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030020
21 if (read_timeout != -1){
22 connection.setReadTimeout(read_timeout*1000)
23 }
Jakub Josef79ecec32017-02-17 14:36:28 +010024 if (method != 'GET') {
25 connection.setRequestMethod(method)
26 }
27
28 if (data) {
29 headers['Content-Type'] = 'application/json'
30 }
31
32 headers['User-Agent'] = 'jenkins-groovy'
33 headers['Accept'] = 'application/json'
34
35 for (header in headers) {
36 connection.setRequestProperty(header.key, header.value)
37 }
38
39 if (data) {
40 connection.setDoOutput(true)
41 if (data instanceof String) {
42 dataStr = data
43 } else {
44 dataStr = new groovy.json.JsonBuilder(data).toString()
45 }
Jakub Josef66976f62017-04-24 16:32:23 +020046 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
47 println("[HTTP] Request URL: ${url}, method: ${method}, headers: ${headers}, content: ${dataStr}")
48 }
Jakub Josef79ecec32017-02-17 14:36:28 +010049 def output = new OutputStreamWriter(connection.outputStream)
Jakub Josef79ecec32017-02-17 14:36:28 +010050 output.write(dataStr)
51 output.close()
52 }
53
54 if ( connection.responseCode == 200 ) {
55 response = connection.inputStream.text
56 try {
57 response_content = new groovy.json.JsonSlurperClassic().parseText(response)
Alexandr Lovtsovf47034a2021-01-02 14:09:56 +030058 } catch (groovy.json.JsonException|java.lang.NullPointerException e) {
59 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
60 println("[HTTP] Cought exception while trying parsing response as JSON: ${e}")
61 }
Jakub Josef79ecec32017-02-17 14:36:28 +010062 response_content = response
63 }
Jakub Josef66976f62017-04-24 16:32:23 +020064 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
65 println("[HTTP] Response: code ${connection.responseCode}")
66 }
Jakub Josef79ecec32017-02-17 14:36:28 +010067 return response_content
68 } else {
Jakub Josef66976f62017-04-24 16:32:23 +020069 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
70 println("[HTTP] Response: code ${connection.responseCode}")
71 }
Jakub Josef79ecec32017-02-17 14:36:28 +010072 throw new Exception(connection.responseCode + ": " + connection.inputStream.text)
73 }
Jakub Josef79ecec32017-02-17 14:36:28 +010074}
75
76/**
77 * Make HTTP GET request
78 *
79 * @param url URL which will requested
80 * @param data JSON data to PUT
81 */
82def sendHttpGetRequest(url, data = null, headers = [:]) {
83 return sendHttpRequest(url, 'GET', data, headers)
84}
85
86/**
87 * Make HTTP POST request
88 *
89 * @param url URL which will requested
90 * @param data JSON data to PUT
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030091 * @param read_timeout http session read timeout
Jakub Josef79ecec32017-02-17 14:36:28 +010092 */
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030093def sendHttpPostRequest(url, data = null, headers = [:], read_timeout=-1) {
94 return sendHttpRequest(url, 'POST', data, headers, read_timeout)
Jakub Josef79ecec32017-02-17 14:36:28 +010095}
96
97/**
98 * Make HTTP PUT request
99 *
100 * @param url URL which will requested
101 * @param data JSON data to PUT
102 */
103def sendHttpPutRequest(url, data = null, headers = [:]) {
104 return sendHttpRequest(url, 'PUT', data, headers)
105}
106
107/**
108 * Make HTTP DELETE request
109 *
110 * @param url URL which will requested
111 * @param data JSON data to PUT
112 */
113def sendHttpDeleteRequest(url, data = null, headers = [:]) {
114 return sendHttpRequest(url, 'DELETE', data, headers)
115}
116
117/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300118 * Make generic call using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100119 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300120 * @param base connection object, map with 'url' and optional 'authToken' keys
121 * @param uri URI which will be appended to connection base URL
122 * @param method HTTP method to use (default GET)
123 * @param data JSON data to POST, PUT or PATCH
124 * @param headers Map of additional request headers
Jakub Josef79ecec32017-02-17 14:36:28 +0100125 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300126def restCall(base, uri, method = 'GET', data = null, headers = [:]) {
127 def connection = new URL("${base.url}${uri}").openConnection()
Jakub Josef79ecec32017-02-17 14:36:28 +0100128 if (method != 'GET') {
129 connection.setRequestMethod(method)
130 }
131
132 connection.setRequestProperty('User-Agent', 'jenkins-groovy')
133 connection.setRequestProperty('Accept', 'application/json')
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300134 if (base.authToken) {
135 // XXX: removeme, explicitly use headers instead
136 connection.setRequestProperty('X-Auth-Token', base.authToken)
Jakub Josef79ecec32017-02-17 14:36:28 +0100137 }
138
139 for (header in headers) {
140 connection.setRequestProperty(header.key, header.value)
141 }
142
143 if (data) {
144 connection.setDoOutput(true)
145 if (data instanceof String) {
146 dataStr = data
147 } else {
148 connection.setRequestProperty('Content-Type', 'application/json')
149 dataStr = new groovy.json.JsonBuilder(data).toString()
150 }
151 def out = new OutputStreamWriter(connection.outputStream)
152 out.write(dataStr)
153 out.close()
154 }
155
156 if ( connection.responseCode >= 200 && connection.responseCode < 300 ) {
157 res = connection.inputStream.text
158 try {
159 return new groovy.json.JsonSlurperClassic().parseText(res)
160 } catch (Exception e) {
161 return res
162 }
163 } else {
164 throw new Exception(connection.responseCode + ": " + connection.inputStream.text)
165 }
166}
167
168/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300169 * Make GET request using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100170 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300171 * @param base connection object, map with 'url' and optional 'authToken' keys
172 * @param uri URI which will be appended to server base URL
Jakub Josef79ecec32017-02-17 14:36:28 +0100173 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300174def restGet(base, uri, data = null, headers = [:]) {
175 return restCall(base, uri, 'GET', data, headers)
Jakub Josef79ecec32017-02-17 14:36:28 +0100176}
177
178/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300179 * Make POST request using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100180 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300181 * @param base connection object, map with 'url' and optional 'authToken' keys
182 * @param uri URI which will be appended to server base URL
183 * @param data JSON Data to POST
184 */
185def restPost(base, uri, data = null, headers = ['Accept': '*/*']) {
186 return restCall(base, uri, 'POST', data, headers)
187}
188
189/**
190 * Make PUT request using REST API and return parsed JSON
191 *
192 * @param base connection object, map with 'url' and optional 'authToken' keys
193 * @param uri URI which will be appended to server base URL
Jakub Josef79ecec32017-02-17 14:36:28 +0100194 * @param data JSON Data to PUT
195 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300196def restPut(base, uri, data = null, headers = ['Accept': '*/*']) {
197 return restCall(base, uri, 'PUT', data, headers)
Jakub Josef79ecec32017-02-17 14:36:28 +0100198}
Jakub Josefab6bf1a2017-03-17 15:46:06 +0100199
200/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300201 * Make PATCH request using REST API and return parsed JSON
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200202 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300203 * @param base connection object, map with 'url' and optional 'authToken' keys
204 * @param uri URI which will be appended to server base URL
205 * @param data JSON Data to PUT
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200206 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300207def restPatch(base, uri, data = null, headers = ['Accept': '*/*']) {
208 return restCall(base, uri, 'PATCH', data, headers)
209}
210
211/**
212 * Make DELETE request using REST API and return parsed JSON
213 *
214 * @param base connection object, map with 'url' and optional 'authToken' keys
215 * @param uri URI which will be appended to server base URL
216 */
217def restDelete(base, uri, data = null, headers = [:]) {
218 return restCall(base, uri, 'DELETE', data, headers)
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200219}
220
221/**
Jakub Josefab6bf1a2017-03-17 15:46:06 +0100222 * Set HTTP and HTTPS proxy for running JVM
223 * @param host HTTP proxy host
224 * @param port HTTP proxy port
225 * @param nonProxyHosts proxy excluded hosts, optional, default *.local
226 */
227def enableHttpProxy(host, port, nonProxyHosts="*.local"){
228 System.getProperties().put("proxySet", "true")
229 System.getProperties().put("http.proxyHost", host)
230 System.getProperties().put("http.proxyPort", port)
231 System.getProperties().put("https.proxyHost", host)
232 System.getProperties().put("https.proxyPort", port)
233 System.getProperties().put("http.nonProxyHosts", nonProxyHosts)
234 System.getProperties().put("https.nonProxyHosts", nonProxyHosts)
235}
236/**
237 * Disable HTTP and HTTPS proxy for running JVM
238 */
239def disableHttpProxy(){
240 System.getProperties().put("proxySet", "false")
241 System.getProperties().remove("http.proxyHost")
242 System.getProperties().remove("http.proxyPort")
243 System.getProperties().remove("https.proxyHost")
244 System.getProperties().remove("https.proxyPort")
245 System.getProperties().remove("http.nonProxyHosts")
246 System.getProperties().remove("https.nonProxyHosts")
247}
Alexander Evseev6ef58892018-04-17 17:46:40 +0200248
249/**
250 * Make HTTP request to the specified URL
251 *
252 * @param url URL to do HTTP request to
253 * @param method HTTP method to execute (`GET` by default)
254 * @param credsId Jenkins credentials ID to use for authorization
255 * @param pushData Data to send
256 * @param pushType MIME-type of pushData
257 * @param params Custom HTTP-headers
258 *
259 * @return Array containing return code and text
260 *
261 * @exception org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException
262 */
263def methodCall(String url, String method = 'GET', String credsId = '',
264 String pushData = '', String pushType = '', Map params = [:]) {
265
266 // Connection object
267 def httpReq = new URI(url).normalize().toURL().openConnection()
268 httpReq.setRequestMethod(method)
269
270 // Timeouts
271 httpReq.setConnectTimeout(10*1000) // milliseconds
272 httpReq.setReadTimeout(600*1000) // milliseconds
273
274 // Add authentication data
275 if (credsId) {
276 String authHeader = ''
277 def cred = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
278 com.cloudbees.plugins.credentials.impl.BaseStandardCredentials.class,
279 jenkins.model.Jenkins.instance).findAll {it.id == credsId}[0]
280 if (cred.class == com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl.class) {
281 authHeader = 'Basic ' + "${cred.getUsername()}:${cred.getPassword()}".getBytes('UTF-8').encodeBase64().toString()
282 } else if (cred.class == org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl.class) {
283 authHeader = 'Bearer ' + cred.getSecret()
284 //params << ['X-JFrog-Art-Api': cred.getSecret()]
285 }
286 params << ['Authorization': authHeader]
287 }
288
289 // Add custom headers if any
290 for (param in params) {
291 httpReq.setRequestProperty(param.key, param.value.toString())
292 }
293
294 // Do request
295 try {
296 if (pushData) {
297 httpReq.setRequestProperty('Content-Type', pushType ?: 'application/x-www-form-urlencoded')
298 if (method == 'GET') { // override incorrect method if pushData is passed
299 httpReq.setRequestMethod('POST')
300 }
301 httpReq.setDoOutput(true)
302 httpReq.getOutputStream().write(pushData.getBytes('UTF-8'))
303 } else {
304 httpReq.connect()
305 }
306 } catch (org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException e) {
307 throw e // show sandbox errors
308 } catch (Exception e) {
309 echo "Cauhgt '${e.class.name}' error: ${e.getMessage()}"
310 return [ -1, e.getMessage() ]
311 }
312
313 // Handle return data
314 int respCode = httpReq.getResponseCode()
315 String respText = ''
316 if (respCode >= 400) {
317 respText = httpReq.getErrorStream().getText() ?: httpReq.getResponseMessage()
318 } else {
319 respText = httpReq.getInputStream().getText()
320 }
321
322 // Return result as a tuple of response code and text
323 return [respCode, respText]
324}
325
326/**
327 * Make HTTP GET request to the specified URL
328 *
329 * @param url URL to do HTTP request to
330 * @param credsId Jenkins credentials ID to use for authorization
331 * @param params Custom HTTP-headers
332 *
333 * @return Array containing return code and text
334 */
335def doGet(String url, String credsId = '', Map params = [:]) {
336 return methodCall(url, 'GET', credsId, null, null, params)
337}
338
339/**
340 * Make HTTP POST request to the specified URL
341 *
342 * @param url URL to do HTTP request to
343 * @param credsId Jenkins credentials ID to use for authorization
344 * @param pushData Data to send
345 * @param pushType MIME-type of pushData
346 * @param params Custom HTTP-headers
347 *
348 * @return Array containing return code and text
349 */
350def doPost(String url, String credsId = '',
351 String pushData = '', String pushType = '', Map params = [:]) {
352 return methodCall(url, 'POST', credsId, pushData, pushType, params)
353}
354
355/**
356 * Make HTTP PUT request to the specified URL
357 *
358 * @param url URL to do HTTP request to
359 * @param credsId Jenkins credentials ID to use for authorization
360 * @param pushData Data to send
361 * @param pushType MIME-type of pushData
362 * @param params Custom HTTP-headers
363 *
364 * @return Array containing return code and text
365 */
366def doPut(String url, String credsId = '',
367 String pushData = '', String pushType = '', Map params = [:]) {
368 return methodCall(url, 'PUT', credsId, pushData, pushType, params)
369}
370
371/**
372 * Make HTTP DELETE request to the specified URL
373 *
374 * @param url URL to do HTTP request to
375 * @param credsId Jenkins credentials ID to use for authorization
376 * @param params Custom HTTP-headers
377 *
378 * @return Array containing return code and text
379 */
380def doDelete(String url, String credsId = '', Map params = [:]) {
381 return methodCall(url, 'DELETE', credsId, null, null, params)
382}