1# -*- coding: utf-8 -*- 2# Copyright: (c) 2019, XLAB Steampunk <steampunk@xlab.si> 3# 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9import json 10 11try: 12 from ssl import CertificateError 13except ImportError: 14 # This will never match the ssl exception, which will cause exception to 15 # bubble up the call stack. 16 class CertificateError(Exception): 17 pass 18 19from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError 20from ansible.module_utils.urls import open_url 21 22from . import errors, debug 23 24 25class Response: 26 def __init__(self, status, data): 27 self.status = status 28 self.data = data 29 self._json = None 30 31 @property 32 def json(self): 33 if self._json is None: 34 try: 35 self._json = json.loads(self.data) 36 except ValueError: # Cannot use JSONDecodeError here (python 2) 37 self._json = None 38 39 return self._json 40 41 42def request(method, url, payload=None, data=None, headers=None, **kwargs): 43 if payload is not None: 44 data = json.dumps(payload, separators=(",", ":")) 45 headers = dict(headers or {}, **{"content-type": "application/json"}) 46 47 try: 48 raw_resp = open_url( 49 method=method, url=url, data=data, headers=headers, **kwargs 50 ) 51 resp = Response(raw_resp.getcode(), raw_resp.read()) 52 debug.log_request(method, url, payload, resp) 53 return resp 54 except HTTPError as e: 55 # This is not an error, since client consumers might be able to 56 # work around/expect non 20x codes. 57 resp = Response(e.code, e.reason) 58 debug.log_request(method, url, payload, resp) 59 return resp 60 except URLError as e: 61 debug.log_request(method, url, payload, comment=e.reason) 62 raise errors.HttpError( 63 "{0} request failed: {1}".format(method, e.reason), 64 ) 65 except CertificateError as e: 66 raise errors.HttpError("Certificate error: {0}".format(e)) 67