def test_httpbackoff_exception(self): args = [ 30 ] kwargs = { "backoff_period": 30 } with pytest.raises(HttpBackoff): raise HttpBackoff(*args) with pytest.raises(DatadogException): raise HttpBackoff(*args) with pytest.raises(HttpBackoff): raise HttpBackoff(**kwargs) with pytest.raises(DatadogException): raise HttpBackoff(**kwargs)
def request(cls, method, path, body=None, attach_host_name=False, response_formatter=None, error_formatter=None, **params): """ Make an HTTP API request :param method: HTTP method to use to contact API endpoint :type method: HTTP method string :param path: API endpoint url :type path: url :param body: dictionnary to be sent in the body of the request :type body: dictionary :param response_formatter: function to format JSON response from HTTP API request :type response_formatter: JSON input function :param error_formatter: function to format JSON error response from HTTP API request :type error_formatter: JSON input function :param attach_host_name: link the new resource object to the host name :type attach_host_name: bool :param params: dictionnary to be sent in the query string of the request :type params: dictionary :returns: JSON or formated response from HTTP API request """ try: # Check if it's ok to submit if not cls._should_submit(): raise HttpBackoff( "Too many timeouts. Won't try again for {1} seconds.". format(*cls._backoff_status())) # Import API, User and HTTP settings from datadog.api import _api_key, _application_key, _api_host, \ _swallow, _host_name, _proxies, _max_retries, _timeout # Check keys and add then to params if _api_key is None: raise ApiNotInitialized( "API key is not set." " Please run 'initialize' method first.") params['api_key'] = _api_key if _application_key: params['application_key'] = _application_key # Construct the url url = "%s/api/%s/%s" % (_api_host, cls._api_version, path.lstrip("/")) # Attach host name to body if attach_host_name and body: # Is it a 'series' list of objects ? if 'series' in body: # Adding the host name to all objects for obj_params in body['series']: if 'host' not in obj_params: obj_params['host'] = _host_name else: if 'host' not in body: body['host'] = _host_name # If defined, make sure tags are defined as a comma-separated string if 'tags' in params and isinstance(params['tags'], list): params['tags'] = ','.join(params['tags']) # Process the body, if necessary headers = {} if isinstance(body, dict): body = json.dumps(body) headers['Content-Type'] = 'application/json' # Process requesting start_time = time.time() try: # Use a session to set a max_retries parameters s = requests.Session() http_adapter = requests.adapters.HTTPAdapter( max_retries=_max_retries) s.mount('https://', http_adapter) # Request result = s.request(method, url, headers=headers, params=params, data=body, timeout=_timeout, proxies=_proxies) result.raise_for_status() except requests.ConnectionError as e: raise ClientError("Could not request %s %s%s: %s" % (method, _api_host, url, e)) except requests.exceptions.Timeout as e: cls._timeout_counter += 1 raise HttpTimeout('%s %s timed out after %d seconds.' % (method, url, _timeout)) except requests.exceptions.HTTPError as e: if e.response.status_code == 404 or e.response.status_code == 400: pass else: raise except TypeError as e: raise TypeError( "Your installed version of 'requests' library seems not compatible with" "Datadog's usage. We recommand upgrading it ('pip install -U requests')." "If you need help or have any question, please contact [email protected]" ) # Request succeeded: log it and reset the timeout counter duration = round((time.time() - start_time) * 1000., 4) log.info("%s %s %s (%sms)" % (result.status_code, method, url, duration)) cls._timeout_counter = 0 # Format response content content = result.content if content: try: if is_p3k(): response_obj = json.loads(content.decode('utf-8')) else: response_obj = json.loads(content) except ValueError: raise ValueError( 'Invalid JSON response: {0}'.format(content)) if response_obj and 'errors' in response_obj: raise ApiError(response_obj) else: response_obj = None if response_formatter is None: return response_obj else: return response_formatter(response_obj) except ClientError as e: if _swallow: log.error(str(e)) if error_formatter is None: return {'errors': e.args[0]} else: return error_formatter({'errors': e.args[0]}) else: raise except ApiError as e: if _swallow: for error in e.args[0]['errors']: log.error(str(error)) if error_formatter is None: return e.args[0] else: return error_formatter(e.args[0]) else: raise
def submit(cls, method, path, api_version=None, body=None, attach_host_name=False, response_formatter=None, error_formatter=None, suppress_response_errors_on_codes=None, compress_payload=False, **params): """ Make an HTTP API request :param method: HTTP method to use to contact API endpoint :type method: HTTP method string :param path: API endpoint url :type path: url :param api_version: The API version used :param body: dictionary to be sent in the body of the request :type body: dictionary :param response_formatter: function to format JSON response from HTTP API request :type response_formatter: JSON input function :param error_formatter: function to format JSON error response from HTTP API request :type error_formatter: JSON input function :param attach_host_name: link the new resource object to the host name :type attach_host_name: bool :param suppress_response_errors_on_codes: suppress ApiError on `errors` key in the response for the given HTTP status codes :type suppress_response_errors_on_codes: None|list(int) :param compress_payload: compress the payload using zlib :type compress_payload: bool :param params: dictionary to be sent in the query string of the request :type params: dictionary :returns: JSON or formated response from HTTP API request """ try: # Check if it's ok to submit if not cls._should_submit(): _, backoff_time_left = cls._backoff_status() raise HttpBackoff(backoff_time_left) # Import API, User and HTTP settings from datadog.api import _api_key, _application_key, _api_host, \ _mute, _host_name, _proxies, _max_retries, _timeout, \ _cacert, _return_raw_response # Check keys and add then to params if _api_key is None: raise ApiNotInitialized("API key is not set." " Please run 'initialize' method first.") # Set api and app keys in headers headers = {} headers['DD-API-KEY'] = _api_key if _application_key: headers['DD-APPLICATION-KEY'] = _application_key # Check if the api_version is provided if not api_version: api_version = _api_version # set api and app keys in params only for some endpoints and thus remove keys from headers # as they cannot be set in both params and headers if cls._set_api_and_app_keys_in_params(api_version, path): params['api_key'] = _api_key del headers['DD-API-KEY'] if _application_key: params['application_key'] = _application_key del headers['DD-APPLICATION-KEY'] # Attach host name to body if attach_host_name and body: # Is it a 'series' list of objects ? if 'series' in body: # Adding the host name to all objects for obj_params in body['series']: if obj_params.get('host', "") == "": obj_params['host'] = _host_name else: if body.get('host', "") == "": body['host'] = _host_name # If defined, make sure tags are defined as a comma-separated string if 'tags' in params and isinstance(params['tags'], list): tag_list = normalize_tags(params['tags']) params['tags'] = ','.join(tag_list) # If defined, make sure monitor_ids are defined as a comma-separated string if 'monitor_ids' in params and isinstance(params['monitor_ids'], list): params['monitor_ids'] = ','.join(str(i) for i in params['monitor_ids']) # Process the body, if necessary if isinstance(body, dict): body = json.dumps(body, sort_keys=cls._sort_keys) headers['Content-Type'] = 'application/json' if compress_payload: body = zlib.compress(body.encode("utf-8")) headers["Content-Encoding"] = "deflate" # Construct the URL url = construct_url(_api_host, api_version, path) # Process requesting start_time = time.time() result = cls._get_http_client().request( method=method, url=url, headers=headers, params=params, data=body, timeout=_timeout, max_retries=_max_retries, proxies=_proxies, verify=_cacert ) # Request succeeded: log it and reset the timeout counter duration = round((time.time() - start_time) * 1000., 4) log.info("%s %s %s (%sms)" % (result.status_code, method, url, duration)) cls._timeout_counter = 0 # Format response content content = result.content if content: try: if is_p3k(): response_obj = json.loads(content.decode('utf-8')) else: response_obj = json.loads(content) except ValueError: raise ValueError('Invalid JSON response: {0}'.format(content)) # response_obj can be a bool and not a dict if isinstance(response_obj, dict): if response_obj and 'errors' in response_obj: # suppress ApiError when specified and just return the response if not (suppress_response_errors_on_codes and result.status_code in suppress_response_errors_on_codes): raise ApiError(response_obj) else: response_obj = None if response_formatter is not None: response_obj = response_formatter(response_obj) if _return_raw_response: return response_obj, result else: return response_obj except HttpTimeout: cls._timeout_counter += 1 raise except ClientError as e: if _mute: log.error(str(e)) if error_formatter is None: return {'errors': e.args[0]} else: return error_formatter({'errors': e.args[0]}) else: raise except ApiError as e: if _mute: for error in (e.args[0].get('errors') or []): log.error(error) if error_formatter is None: return e.args[0] else: return error_formatter(e.args[0]) else: raise
def submit(cls, method, path, body=None, attach_host_name=False, response_formatter=None, error_formatter=None, **params): """ Make an HTTP API request :param method: HTTP method to use to contact API endpoint :type method: HTTP method string :param path: API endpoint url :type path: url :param body: dictionary to be sent in the body of the request :type body: dictionary :param response_formatter: function to format JSON response from HTTP API request :type response_formatter: JSON input function :param error_formatter: function to format JSON error response from HTTP API request :type error_formatter: JSON input function :param attach_host_name: link the new resource object to the host name :type attach_host_name: bool :param params: dictionary to be sent in the query string of the request :type params: dictionary :returns: JSON or formated response from HTTP API request """ try: # Check if it's ok to submit if not cls._should_submit(): _, backoff_time_left = cls._backoff_status() raise HttpBackoff(backoff_time_left) # Import API, User and HTTP settings from datadog.api import _api_key, _application_key, _api_host, \ _mute, _host_name, _proxies, _max_retries, _timeout, \ _cacert # Check keys and add then to params if _api_key is None: raise ApiNotInitialized( "API key is not set." " Please run 'initialize' method first.") params['api_key'] = _api_key if _application_key: params['application_key'] = _application_key # Attach host name to body if attach_host_name and body: # Is it a 'series' list of objects ? if 'series' in body: # Adding the host name to all objects for obj_params in body['series']: if obj_params.get('host', "") == "": obj_params['host'] = _host_name else: if body.get('host', "") == "": body['host'] = _host_name # If defined, make sure tags are defined as a comma-separated string if 'tags' in params and isinstance(params['tags'], list): params['tags'] = ','.join(params['tags']) # Process the body, if necessary headers = {} if isinstance(body, dict): body = json.dumps(body) headers['Content-Type'] = 'application/json' # Construct the URL url = "{api_host}/api/{api_version}/{path}".format( api_host=_api_host, api_version=cls._api_version, path=path.lstrip("/"), ) # Process requesting start_time = time.time() result = cls._get_http_client().request(method=method, url=url, headers=headers, params=params, data=body, timeout=_timeout, max_retries=_max_retries, proxies=_proxies, verify=_cacert) # Request succeeded: log it and reset the timeout counter duration = round((time.time() - start_time) * 1000., 4) log.info("%s %s %s (%sms)" % (result.status_code, method, url, duration)) cls._timeout_counter = 0 # Format response content content = result.content if content: try: if is_p3k(): response_obj = json.loads(content.decode('utf-8')) else: response_obj = json.loads(content) except ValueError: raise ValueError( 'Invalid JSON response: {0}'.format(content)) if response_obj and 'errors' in response_obj: raise ApiError(response_obj) else: response_obj = None if response_formatter is None: return response_obj else: return response_formatter(response_obj) except HttpTimeout: cls._timeout_counter += 1 raise except ClientError as e: if _mute: log.error(str(e)) if error_formatter is None: return {'errors': e.args[0]} else: return error_formatter({'errors': e.args[0]}) else: raise except ApiError as e: if _mute: for error in e.args[0]['errors']: log.error(str(error)) if error_formatter is None: return e.args[0] else: return error_formatter(e.args[0]) else: raise