예제 #1
0
    def request(self,
                method,
                url,
                query_params=None,
                headers=None,
                body=None,
                post_params=None,
                _preload_content=True,
                _request_timeout=None):
        """Perform requests.

        :param method: http request method
        :param url: http request url
        :param query_params: query parameters in the url
        :param headers: http request headers
        :param body: request json body, for `application/json`
        :param post_params: request post parameters,
                            `application/x-www-form-urlencoded`
                            and `multipart/form-data`
        :param _preload_content: if False, the urllib3.HTTPResponse object will
                                 be returned without reading/decoding response
                                 data. Default is True.
        :param _request_timeout: timeout setting for this request. If one
                                 number provided, it will be total request
                                 timeout. It can also be a pair (tuple) of
                                 (connection, read) timeouts.
        """
        method = method.upper()
        assert method in [
            'GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH', 'OPTIONS'
        ]

        if post_params and body:
            raise ApiValueError(
                "body parameter cannot be used with post_params parameter.")

        post_params = post_params or {}
        headers = headers or {}

        timeout = None
        if _request_timeout:
            if isinstance(_request_timeout, (int, ) if six.PY3 else
                          (int, long)):  # noqa: E501,F821
                timeout = urllib3.Timeout(total=_request_timeout)
            elif (isinstance(_request_timeout, tuple)
                  and len(_request_timeout) == 2):
                timeout = urllib3.Timeout(connect=_request_timeout[0],
                                          read=_request_timeout[1])

        if 'Content-Type' not in headers:
            headers['Content-Type'] = 'application/json'

        try:
            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
                if query_params:
                    url += '?' + urlencode(query_params)
                if re.search('json', headers['Content-Type'], re.IGNORECASE):
                    request_body = None
                    if body is not None:
                        request_body = json.dumps(body)
                    r = self.pool_manager.request(
                        method,
                        url,
                        body=request_body,
                        preload_content=_preload_content,
                        timeout=timeout,
                        headers=headers)
                elif headers[
                        'Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501
                    r = self.pool_manager.request(
                        method,
                        url,
                        fields=post_params,
                        encode_multipart=False,
                        preload_content=_preload_content,
                        timeout=timeout,
                        headers=headers)
                elif headers['Content-Type'] == 'multipart/form-data':
                    # must del headers['Content-Type'], or the correct
                    # Content-Type which generated by urllib3 will be
                    # overwritten.
                    del headers['Content-Type']
                    r = self.pool_manager.request(
                        method,
                        url,
                        fields=post_params,
                        encode_multipart=True,
                        preload_content=_preload_content,
                        timeout=timeout,
                        headers=headers)
                # Pass a `string` parameter directly in the body to support
                # other content types than Json when `body` argument is
                # provided in serialized form
                elif isinstance(body, str) or isinstance(body, bytes):
                    request_body = body
                    r = self.pool_manager.request(
                        method,
                        url,
                        body=request_body,
                        preload_content=_preload_content,
                        timeout=timeout,
                        headers=headers)
                else:
                    # Cannot generate the request from given parameters
                    msg = """Cannot prepare a request message for provided
                             arguments. Please check that your arguments match
                             declared content type."""
                    raise ApiException(status=0, reason=msg)
            # For `GET`, `HEAD`
            else:
                r = self.pool_manager.request(method,
                                              url,
                                              fields=query_params,
                                              preload_content=_preload_content,
                                              timeout=timeout,
                                              headers=headers)
        except urllib3.exceptions.SSLError as e:
            msg = "{0}\n{1}".format(type(e).__name__, str(e))
            raise ApiException(status=0, reason=msg)

        if _preload_content:
            r = RESTResponse(r)

            # log response body
            logger.debug("response body: %s", r.data)

        if not 200 <= r.status <= 299:
            raise ApiException(http_resp=r)

        return r
예제 #2
0
    def _enrich_single_command_using_insights(self, request_id: str, command_type: str, asat: Timestamp,
                                              **kwargs) -> List[Tuple[str, str, str, Timestamp, Timestamp]]:
        """
        The responsibility of this function is that given a request_id and command_type it determines
        which portfolio was added or removed from a group and at what effectiveAt time.

        :param str request_id: The request_id for the command
        :param str command_type: The type of command issued
        :param Timestamp asat: The asAt date of the command

        :return: List[Tuple[str, str, str, Timestamp, Timestamp]] portfolio_scope, portfolio_code, command_type,
        asat, effective_date: The identifier for the Portfolio and command type, asAt and effectiveAt date of the command
        """
        start = time.time()
        # Get the API URL for the Insights API from the LUSID API URL
        api_url = self.api_factory.api_client.configuration.host
        request_url = api_url.rstrip('api') + f"insights/api/requests/{request_id}/request"

        # Get the request payload, it might not be available straight away if the command was just issued
        status_code = 404
        retries = 0
        while status_code == 404:

            raw_response = requests.get(
                url=request_url,
                headers={"Authorization": f"Bearer {self.api_factory.api_client.configuration.access_token}"}
            )
            status_code = raw_response.status_code
            logging.debug(f"Status code {raw_response.status_code} and response of {raw_response} with headers "
                          f"{raw_response.headers} trying to enrich Log for {request_id}")

            if status_code == 404 and retries < 5:
                retries += 1
                time.sleep(2)
            elif 200 <= status_code <= 299:
                break
            else:
                raise ApiException(status=status_code)

        response = json.loads(raw_response.text)
        request_url = response["url"]
        url_split = request_url.split("/")
        command_type = command_type.lower()
        # Depending on the command type, parse out the relevant information from the request
        if command_type == CommandDescriptions.add_command:
            effective_date = dateutil.parser.parse(urllib.parse.unquote(url_split[-1].split("=")[1]))
            request_body = json.loads(response["body"])
            portfolio_scopes = [request_body["scope"]]
            portfolio_codes = [request_body["code"]]

        elif command_type == CommandDescriptions.remove_command:
            portfolio_info_start_index = url_split.index("portfolios")
            portfolio_info = url_split[portfolio_info_start_index:]
            portfolio_scopes = [portfolio_info[1]]
            portfolio_codes = [portfolio_info[2].split("?")[0]]
            effective_date = dateutil.parser.parse(urllib.parse.unquote(portfolio_info[2].split("=")[1]))

        elif command_type == CommandDescriptions.create_command:
            # This command is converted into 0 or more Add portfolio to group commands which have the same impact
            request_body = json.loads(response["body"])
            effective_date = dateutil.parser.parse(request_body["created"])
            if "values" in request_body:
                portfolio_scopes = [resource_id["scope"] for resource_id in request_body["values"]]
                portfolio_codes = [resource_id["code"] for resource_id in request_body["values"]]
            else:
                portfolio_scopes = []
                portfolio_codes = []
            command_type = CommandDescriptions.add_command

        logging.debug(f"Getting Insight Log for {request_id} Took: {time.time() - start}")

        return [
            (portfolio_scope, portfolio_code, command_type, asat, effective_date)
            for portfolio_scope, portfolio_code in zip(portfolio_scopes, portfolio_codes)
        ]