blob: b752b4259d0b0f8460a64f1bd49dfbaf650a44b3 [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)
58 } catch (groovy.json.JsonException e) {
59 response_content = response
60 }
Jakub Josef66976f62017-04-24 16:32:23 +020061 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
62 println("[HTTP] Response: code ${connection.responseCode}")
63 }
Jakub Josef79ecec32017-02-17 14:36:28 +010064 return response_content
65 } else {
Jakub Josef66976f62017-04-24 16:32:23 +020066 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
67 println("[HTTP] Response: code ${connection.responseCode}")
68 }
Jakub Josef79ecec32017-02-17 14:36:28 +010069 throw new Exception(connection.responseCode + ": " + connection.inputStream.text)
70 }
Jakub Josef79ecec32017-02-17 14:36:28 +010071}
72
73/**
74 * Make HTTP GET request
75 *
76 * @param url URL which will requested
77 * @param data JSON data to PUT
78 */
79def sendHttpGetRequest(url, data = null, headers = [:]) {
80 return sendHttpRequest(url, 'GET', data, headers)
81}
82
83/**
84 * Make HTTP POST request
85 *
86 * @param url URL which will requested
87 * @param data JSON data to PUT
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030088 * @param read_timeout http session read timeout
Jakub Josef79ecec32017-02-17 14:36:28 +010089 */
Vasyl Saienkoe36ab7c2017-07-17 14:35:48 +030090def sendHttpPostRequest(url, data = null, headers = [:], read_timeout=-1) {
91 return sendHttpRequest(url, 'POST', data, headers, read_timeout)
Jakub Josef79ecec32017-02-17 14:36:28 +010092}
93
94/**
95 * Make HTTP PUT request
96 *
97 * @param url URL which will requested
98 * @param data JSON data to PUT
99 */
100def sendHttpPutRequest(url, data = null, headers = [:]) {
101 return sendHttpRequest(url, 'PUT', data, headers)
102}
103
104/**
105 * Make HTTP DELETE request
106 *
107 * @param url URL which will requested
108 * @param data JSON data to PUT
109 */
110def sendHttpDeleteRequest(url, data = null, headers = [:]) {
111 return sendHttpRequest(url, 'DELETE', data, headers)
112}
113
114/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300115 * Make generic call using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100116 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300117 * @param base connection object, map with 'url' and optional 'authToken' keys
118 * @param uri URI which will be appended to connection base URL
119 * @param method HTTP method to use (default GET)
120 * @param data JSON data to POST, PUT or PATCH
121 * @param headers Map of additional request headers
Jakub Josef79ecec32017-02-17 14:36:28 +0100122 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300123def restCall(base, uri, method = 'GET', data = null, headers = [:]) {
124 def connection = new URL("${base.url}${uri}").openConnection()
Jakub Josef79ecec32017-02-17 14:36:28 +0100125 if (method != 'GET') {
126 connection.setRequestMethod(method)
127 }
128
129 connection.setRequestProperty('User-Agent', 'jenkins-groovy')
130 connection.setRequestProperty('Accept', 'application/json')
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300131 if (base.authToken) {
132 // XXX: removeme, explicitly use headers instead
133 connection.setRequestProperty('X-Auth-Token', base.authToken)
Jakub Josef79ecec32017-02-17 14:36:28 +0100134 }
135
136 for (header in headers) {
137 connection.setRequestProperty(header.key, header.value)
138 }
139
140 if (data) {
141 connection.setDoOutput(true)
142 if (data instanceof String) {
143 dataStr = data
144 } else {
145 connection.setRequestProperty('Content-Type', 'application/json')
146 dataStr = new groovy.json.JsonBuilder(data).toString()
147 }
148 def out = new OutputStreamWriter(connection.outputStream)
149 out.write(dataStr)
150 out.close()
151 }
152
153 if ( connection.responseCode >= 200 && connection.responseCode < 300 ) {
154 res = connection.inputStream.text
155 try {
156 return new groovy.json.JsonSlurperClassic().parseText(res)
157 } catch (Exception e) {
158 return res
159 }
160 } else {
161 throw new Exception(connection.responseCode + ": " + connection.inputStream.text)
162 }
163}
164
165/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300166 * Make GET request using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100167 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300168 * @param base connection object, map with 'url' and optional 'authToken' keys
169 * @param uri URI which will be appended to server base URL
Jakub Josef79ecec32017-02-17 14:36:28 +0100170 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300171def restGet(base, uri, data = null, headers = [:]) {
172 return restCall(base, uri, 'GET', data, headers)
Jakub Josef79ecec32017-02-17 14:36:28 +0100173}
174
175/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300176 * Make POST request using REST API and return parsed JSON
Jakub Josef79ecec32017-02-17 14:36:28 +0100177 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300178 * @param base connection object, map with 'url' and optional 'authToken' keys
179 * @param uri URI which will be appended to server base URL
180 * @param data JSON Data to POST
181 */
182def restPost(base, uri, data = null, headers = ['Accept': '*/*']) {
183 return restCall(base, uri, 'POST', data, headers)
184}
185
186/**
187 * Make PUT request using REST API and return parsed JSON
188 *
189 * @param base connection object, map with 'url' and optional 'authToken' keys
190 * @param uri URI which will be appended to server base URL
Jakub Josef79ecec32017-02-17 14:36:28 +0100191 * @param data JSON Data to PUT
192 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300193def restPut(base, uri, data = null, headers = ['Accept': '*/*']) {
194 return restCall(base, uri, 'PUT', data, headers)
Jakub Josef79ecec32017-02-17 14:36:28 +0100195}
Jakub Josefab6bf1a2017-03-17 15:46:06 +0100196
197/**
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300198 * Make PATCH request using REST API and return parsed JSON
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200199 *
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300200 * @param base connection object, map with 'url' and optional 'authToken' keys
201 * @param uri URI which will be appended to server base URL
202 * @param data JSON Data to PUT
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200203 */
Pavlo Shchelokovskyy3170add2018-10-03 22:45:16 +0300204def restPatch(base, uri, data = null, headers = ['Accept': '*/*']) {
205 return restCall(base, uri, 'PATCH', data, headers)
206}
207
208/**
209 * Make DELETE request using REST API and return parsed JSON
210 *
211 * @param base connection object, map with 'url' and optional 'authToken' keys
212 * @param uri URI which will be appended to server base URL
213 */
214def restDelete(base, uri, data = null, headers = [:]) {
215 return restCall(base, uri, 'DELETE', data, headers)
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200216}
217
218/**
Jakub Josefab6bf1a2017-03-17 15:46:06 +0100219 * Set HTTP and HTTPS proxy for running JVM
220 * @param host HTTP proxy host
221 * @param port HTTP proxy port
222 * @param nonProxyHosts proxy excluded hosts, optional, default *.local
223 */
224def enableHttpProxy(host, port, nonProxyHosts="*.local"){
225 System.getProperties().put("proxySet", "true")
226 System.getProperties().put("http.proxyHost", host)
227 System.getProperties().put("http.proxyPort", port)
228 System.getProperties().put("https.proxyHost", host)
229 System.getProperties().put("https.proxyPort", port)
230 System.getProperties().put("http.nonProxyHosts", nonProxyHosts)
231 System.getProperties().put("https.nonProxyHosts", nonProxyHosts)
232}
233/**
234 * Disable HTTP and HTTPS proxy for running JVM
235 */
236def disableHttpProxy(){
237 System.getProperties().put("proxySet", "false")
238 System.getProperties().remove("http.proxyHost")
239 System.getProperties().remove("http.proxyPort")
240 System.getProperties().remove("https.proxyHost")
241 System.getProperties().remove("https.proxyPort")
242 System.getProperties().remove("http.nonProxyHosts")
243 System.getProperties().remove("https.nonProxyHosts")
244}
Alexander Evseev6ef58892018-04-17 17:46:40 +0200245
246/**
247 * Make HTTP request to the specified URL
248 *
249 * @param url URL to do HTTP request to
250 * @param method HTTP method to execute (`GET` by default)
251 * @param credsId Jenkins credentials ID to use for authorization
252 * @param pushData Data to send
253 * @param pushType MIME-type of pushData
254 * @param params Custom HTTP-headers
255 *
256 * @return Array containing return code and text
257 *
258 * @exception org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException
259 */
260def methodCall(String url, String method = 'GET', String credsId = '',
261 String pushData = '', String pushType = '', Map params = [:]) {
262
263 // Connection object
264 def httpReq = new URI(url).normalize().toURL().openConnection()
265 httpReq.setRequestMethod(method)
266
267 // Timeouts
268 httpReq.setConnectTimeout(10*1000) // milliseconds
269 httpReq.setReadTimeout(600*1000) // milliseconds
270
271 // Add authentication data
272 if (credsId) {
273 String authHeader = ''
274 def cred = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
275 com.cloudbees.plugins.credentials.impl.BaseStandardCredentials.class,
276 jenkins.model.Jenkins.instance).findAll {it.id == credsId}[0]
277 if (cred.class == com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl.class) {
278 authHeader = 'Basic ' + "${cred.getUsername()}:${cred.getPassword()}".getBytes('UTF-8').encodeBase64().toString()
279 } else if (cred.class == org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl.class) {
280 authHeader = 'Bearer ' + cred.getSecret()
281 //params << ['X-JFrog-Art-Api': cred.getSecret()]
282 }
283 params << ['Authorization': authHeader]
284 }
285
286 // Add custom headers if any
287 for (param in params) {
288 httpReq.setRequestProperty(param.key, param.value.toString())
289 }
290
291 // Do request
292 try {
293 if (pushData) {
294 httpReq.setRequestProperty('Content-Type', pushType ?: 'application/x-www-form-urlencoded')
295 if (method == 'GET') { // override incorrect method if pushData is passed
296 httpReq.setRequestMethod('POST')
297 }
298 httpReq.setDoOutput(true)
299 httpReq.getOutputStream().write(pushData.getBytes('UTF-8'))
300 } else {
301 httpReq.connect()
302 }
303 } catch (org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException e) {
304 throw e // show sandbox errors
305 } catch (Exception e) {
306 echo "Cauhgt '${e.class.name}' error: ${e.getMessage()}"
307 return [ -1, e.getMessage() ]
308 }
309
310 // Handle return data
311 int respCode = httpReq.getResponseCode()
312 String respText = ''
313 if (respCode >= 400) {
314 respText = httpReq.getErrorStream().getText() ?: httpReq.getResponseMessage()
315 } else {
316 respText = httpReq.getInputStream().getText()
317 }
318
319 // Return result as a tuple of response code and text
320 return [respCode, respText]
321}
322
323/**
324 * Make HTTP GET request to the specified URL
325 *
326 * @param url URL to do HTTP request to
327 * @param credsId Jenkins credentials ID to use for authorization
328 * @param params Custom HTTP-headers
329 *
330 * @return Array containing return code and text
331 */
332def doGet(String url, String credsId = '', Map params = [:]) {
333 return methodCall(url, 'GET', credsId, null, null, params)
334}
335
336/**
337 * Make HTTP POST request to the specified URL
338 *
339 * @param url URL to do HTTP request to
340 * @param credsId Jenkins credentials ID to use for authorization
341 * @param pushData Data to send
342 * @param pushType MIME-type of pushData
343 * @param params Custom HTTP-headers
344 *
345 * @return Array containing return code and text
346 */
347def doPost(String url, String credsId = '',
348 String pushData = '', String pushType = '', Map params = [:]) {
349 return methodCall(url, 'POST', credsId, pushData, pushType, params)
350}
351
352/**
353 * Make HTTP PUT request to the specified URL
354 *
355 * @param url URL to do HTTP request to
356 * @param credsId Jenkins credentials ID to use for authorization
357 * @param pushData Data to send
358 * @param pushType MIME-type of pushData
359 * @param params Custom HTTP-headers
360 *
361 * @return Array containing return code and text
362 */
363def doPut(String url, String credsId = '',
364 String pushData = '', String pushType = '', Map params = [:]) {
365 return methodCall(url, 'PUT', credsId, pushData, pushType, params)
366}
367
368/**
369 * Make HTTP DELETE request to the specified URL
370 *
371 * @param url URL to do HTTP request to
372 * @param credsId Jenkins credentials ID to use for authorization
373 * @param params Custom HTTP-headers
374 *
375 * @return Array containing return code and text
376 */
377def doDelete(String url, String credsId = '', Map params = [:]) {
378 return methodCall(url, 'DELETE', credsId, null, null, params)
379}