1*2d57dc69SVladimir Kotal# 2*2d57dc69SVladimir Kotal# CDDL HEADER START 3*2d57dc69SVladimir Kotal# 4*2d57dc69SVladimir Kotal# The contents of this file are subject to the terms of the 5*2d57dc69SVladimir Kotal# Common Development and Distribution License (the "License"). 6*2d57dc69SVladimir Kotal# You may not use this file except in compliance with the License. 7*2d57dc69SVladimir Kotal# 8*2d57dc69SVladimir Kotal# See LICENSE.txt included in this distribution for the specific 9*2d57dc69SVladimir Kotal# language governing permissions and limitations under the License. 10*2d57dc69SVladimir Kotal# 11*2d57dc69SVladimir Kotal# When distributing Covered Code, include this CDDL HEADER in each 12*2d57dc69SVladimir Kotal# file and include the License file at LICENSE.txt. 13*2d57dc69SVladimir Kotal# If applicable, add the following below this CDDL HEADER, with the 14*2d57dc69SVladimir Kotal# fields enclosed by brackets "[]" replaced with your own identifying 15*2d57dc69SVladimir Kotal# information: Portions Copyright [yyyy] [name of copyright owner] 16*2d57dc69SVladimir Kotal# 17*2d57dc69SVladimir Kotal# CDDL HEADER END 18*2d57dc69SVladimir Kotal# 19*2d57dc69SVladimir Kotal 20*2d57dc69SVladimir Kotal# 21*2d57dc69SVladimir Kotal# Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. 22*2d57dc69SVladimir Kotal# 23*2d57dc69SVladimir Kotal 24*2d57dc69SVladimir Kotalimport json 25*2d57dc69SVladimir Kotalimport logging 26*2d57dc69SVladimir Kotal 27*2d57dc69SVladimir Kotalimport requests 28*2d57dc69SVladimir Kotal 29*2d57dc69SVladimir Kotalfrom .patterns import COMMAND_PROPERTY 30*2d57dc69SVladimir Kotalfrom .webutil import get_proxies 31*2d57dc69SVladimir Kotal 32*2d57dc69SVladimir KotalCONTENT_TYPE = 'Content-Type' 33*2d57dc69SVladimir KotalAPPLICATION_JSON = 'application/json' # default 34*2d57dc69SVladimir Kotal 35*2d57dc69SVladimir Kotal 36*2d57dc69SVladimir Kotaldef do_api_call(verb, uri, params=None, headers=None, data=None): 37*2d57dc69SVladimir Kotal """ 38*2d57dc69SVladimir Kotal Perform an API call. Will raise an exception if the request fails. 39*2d57dc69SVladimir Kotal :param verb: string holding HTTP verb 40*2d57dc69SVladimir Kotal :param uri: URI string 41*2d57dc69SVladimir Kotal :param params: request parameters 42*2d57dc69SVladimir Kotal :param headers: HTTP headers dictionary 43*2d57dc69SVladimir Kotal :param data: data or None 44*2d57dc69SVladimir Kotal :return: the result of the handler call, can be None 45*2d57dc69SVladimir Kotal """ 46*2d57dc69SVladimir Kotal logger = logging.getLogger(__name__) 47*2d57dc69SVladimir Kotal 48*2d57dc69SVladimir Kotal handler = getattr(requests, verb.lower()) 49*2d57dc69SVladimir Kotal if handler is None or not callable(handler): 50*2d57dc69SVladimir Kotal raise Exception('Unknown HTTP verb: {}'.format(verb)) 51*2d57dc69SVladimir Kotal 52*2d57dc69SVladimir Kotal logger.debug("{} API call: {} with data '{}' and headers: {}". 53*2d57dc69SVladimir Kotal format(verb, uri, data, headers)) 54*2d57dc69SVladimir Kotal r = handler( 55*2d57dc69SVladimir Kotal uri, 56*2d57dc69SVladimir Kotal data=data, 57*2d57dc69SVladimir Kotal params=params, 58*2d57dc69SVladimir Kotal headers=headers, 59*2d57dc69SVladimir Kotal proxies=get_proxies(uri) 60*2d57dc69SVladimir Kotal ) 61*2d57dc69SVladimir Kotal 62*2d57dc69SVladimir Kotal if r is None: 63*2d57dc69SVladimir Kotal raise Exception("API call failed") 64*2d57dc69SVladimir Kotal 65*2d57dc69SVladimir Kotal r.raise_for_status() 66*2d57dc69SVladimir Kotal 67*2d57dc69SVladimir Kotal return r 68*2d57dc69SVladimir Kotal 69*2d57dc69SVladimir Kotal 70*2d57dc69SVladimir Kotaldef call_rest_api(command, pattern, name): 71*2d57dc69SVladimir Kotal """ 72*2d57dc69SVladimir Kotal Make RESTful API call. Occurrence of the pattern in the URI 73*2d57dc69SVladimir Kotal (first part of the command) or data payload will be replaced by the name. 74*2d57dc69SVladimir Kotal 75*2d57dc69SVladimir Kotal Default content type is application/json. 76*2d57dc69SVladimir Kotal 77*2d57dc69SVladimir Kotal :param command: command (list of URI, HTTP verb, data payload) 78*2d57dc69SVladimir Kotal :param pattern: pattern for command name and/or data substitution 79*2d57dc69SVladimir Kotal :param name: command name 80*2d57dc69SVladimir Kotal :return return value from given requests method 81*2d57dc69SVladimir Kotal """ 82*2d57dc69SVladimir Kotal 83*2d57dc69SVladimir Kotal logger = logging.getLogger(__name__) 84*2d57dc69SVladimir Kotal 85*2d57dc69SVladimir Kotal if not isinstance(command, dict) or command.get(COMMAND_PROPERTY) is None: 86*2d57dc69SVladimir Kotal raise Exception("invalid command") 87*2d57dc69SVladimir Kotal 88*2d57dc69SVladimir Kotal command = command[COMMAND_PROPERTY] 89*2d57dc69SVladimir Kotal 90*2d57dc69SVladimir Kotal uri, verb, data, *_ = command 91*2d57dc69SVladimir Kotal try: 92*2d57dc69SVladimir Kotal headers = command[3] 93*2d57dc69SVladimir Kotal if headers and not isinstance(headers, dict): 94*2d57dc69SVladimir Kotal raise Exception("headers must be a dictionary") 95*2d57dc69SVladimir Kotal except IndexError: 96*2d57dc69SVladimir Kotal headers = {} 97*2d57dc69SVladimir Kotal 98*2d57dc69SVladimir Kotal if headers is None: 99*2d57dc69SVladimir Kotal headers = {} 100*2d57dc69SVladimir Kotal 101*2d57dc69SVladimir Kotal if pattern and name: 102*2d57dc69SVladimir Kotal uri = uri.replace(pattern, name) 103*2d57dc69SVladimir Kotal 104*2d57dc69SVladimir Kotal header_names = [x.lower() for x in headers.keys()] 105*2d57dc69SVladimir Kotal 106*2d57dc69SVladimir Kotal if data: 107*2d57dc69SVladimir Kotal if CONTENT_TYPE.lower() not in header_names: 108*2d57dc69SVladimir Kotal logger.debug("Adding header: {} = {}". 109*2d57dc69SVladimir Kotal format(CONTENT_TYPE, APPLICATION_JSON)) 110*2d57dc69SVladimir Kotal headers[CONTENT_TYPE] = APPLICATION_JSON 111*2d57dc69SVladimir Kotal 112*2d57dc69SVladimir Kotal for (k, v) in headers.items(): 113*2d57dc69SVladimir Kotal if k.lower() == CONTENT_TYPE.lower(): 114*2d57dc69SVladimir Kotal if headers[k].lower() == APPLICATION_JSON.lower(): 115*2d57dc69SVladimir Kotal logger.debug("Converting {} to JSON".format(data)) 116*2d57dc69SVladimir Kotal data = json.dumps(data) 117*2d57dc69SVladimir Kotal break 118*2d57dc69SVladimir Kotal 119*2d57dc69SVladimir Kotal if pattern and name: 120*2d57dc69SVladimir Kotal data = data.replace(pattern, name) 121*2d57dc69SVladimir Kotal logger.debug("entity data: {}".format(data)) 122*2d57dc69SVladimir Kotal 123*2d57dc69SVladimir Kotal return do_api_call(verb, uri, headers=headers, data=data) 124