Example #1
0
    def validate_response(cls, schema, resp, body):
        # Only check the response if the status code is a success code
        # TODO(cyeoh): Eventually we should be able to verify that a failure
        # code if it exists is something that we expect. This is explicitly
        # declared in the V3 API and so we should be able to export this in
        # the response schema. For now we'll ignore it.
        return
        if resp.status in HTTP_SUCCESS + HTTP_REDIRECTION:
            cls.expected_success(schema['status_code'], resp.status)

            # Check the body of a response
            body_schema = schema.get('response_body')
            if body_schema:
                try:
                    jsonschema.validate(body,
                                        body_schema,
                                        cls=JSONSCHEMA_VALIDATOR,
                                        format_checker=FORMAT_CHECKER)
                except jsonschema.ValidationError as ex:
                    msg = ("HTTP response body is invalid (%s)") % ex
                    raise exceptions.InvalidHTTPResponseBody(msg)
            else:
                if body:
                    msg = ("HTTP response body should not exist (%s)") % body
                    raise exceptions.InvalidHTTPResponseBody(msg)

            # Check the header of a response
            header_schema = schema.get('response_header')
            if header_schema:
                try:
                    jsonschema.validate(resp,
                                        header_schema,
                                        cls=JSONSCHEMA_VALIDATOR,
                                        format_checker=FORMAT_CHECKER)
                except jsonschema.ValidationError as ex:
                    msg = ("HTTP response header is invalid (%s)") % ex
                    raise exceptions.InvalidHTTPResponseHeader(msg)
Example #2
0
    def _error_checker(self, method, url, headers, body, resp, resp_body):

        # NOTE(mtreinish): Check for httplib response from glance_http. The
        # object can't be used here because importing httplib breaks httplib2.
        # If another object from a class not imported were passed here as
        # resp this could possibly fail
        if str(type(resp)) == "<type 'instance'>":
            ctype = resp.getheader('content-type')
        else:
            try:
                ctype = resp['content-type']
            # NOTE(mtreinish): Keystone delete user responses doesn't have a
            # content-type header. (They don't have a body) So just pretend it
            # is set.
            except KeyError:
                ctype = 'application/json'

        # It is not an error response
        if resp.status < 400:
            return

        JSON_ENC = ['application/json', 'application/json; charset=utf-8']
        # NOTE(mtreinish): This is for compatibility with Glance and swift
        # APIs. These are the return content types that Glance api v1
        # (and occasionally swift) are using.
        TXT_ENC = [
            'text/plain', 'text/html', 'text/html; charset=utf-8',
            'text/plain; charset=utf-8'
        ]

        if ctype.lower() in JSON_ENC:
            parse_resp = True
        elif ctype.lower() in TXT_ENC:
            parse_resp = False
        else:
            raise exceptions.UnexpectedContentType(str(resp.status), resp=resp)

        if resp.status == 401:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.Unauthorized(resp_body, resp=resp)

        if resp.status == 403:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.Forbidden(resp_body, resp=resp)

        if resp.status == 404:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.NotFound(resp_body, resp=resp)

        if resp.status == 400:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.BadRequest(resp_body, resp=resp)

        if resp.status == 410:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.Gone(resp_body, resp=resp)

        if resp.status == 409:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.Conflict(resp_body, resp=resp)

        if resp.status == 413:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            if self.is_absolute_limit(resp, resp_body):
                raise exceptions.OverLimit(resp_body, resp=resp)
            else:
                raise exceptions.RateLimitExceeded(resp_body, resp=resp)

        if resp.status == 415:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.InvalidContentType(resp_body, resp=resp)

        if resp.status == 422:
            if parse_resp:
                resp_body = self._parse_resp(resp_body)
            raise exceptions.UnprocessableEntity(resp_body, resp=resp)

        if resp.status in (500, 501):
            message = resp_body
            if parse_resp:
                try:
                    resp_body = self._parse_resp(resp_body)
                except ValueError:
                    # If response body is a non-json string message.
                    # Use resp_body as is and raise InvalidResponseBody
                    # exception.
                    raise exceptions.InvalidHTTPResponseBody(message)
                else:
                    if isinstance(resp_body, dict):
                        # I'm seeing both computeFault
                        # and cloudServersFault come back.
                        # Will file a bug to fix, but leave as is for now.
                        if 'cloudServersFault' in resp_body:
                            message = resp_body['cloudServersFault']['message']
                        elif 'computeFault' in resp_body:
                            message = resp_body['computeFault']['message']
                        elif 'error' in resp_body:
                            message = resp_body['error']['message']
                        elif 'message' in resp_body:
                            message = resp_body['message']
                    else:
                        message = resp_body

            if resp.status == 501:
                raise exceptions.NotImplemented(resp_body,
                                                resp=resp,
                                                message=message)
            else:
                raise exceptions.ServerFault(resp_body,
                                             resp=resp,
                                             message=message)

        if resp.status >= 400:
            raise exceptions.UnexpectedResponseCode(str(resp.status),
                                                    resp=resp)
Example #3
0
def validate_URL_response(URL,
                          expected_status_code=200,
                          expected_body=None,
                          HTTPS_verify=True,
                          client_cert_path=None,
                          CA_certs_path=None,
                          request_interval=CONF.load_balancer.build_interval,
                          request_timeout=CONF.load_balancer.build_timeout):
    """Check a URL response (HTTP or HTTPS).

    :param URL: The URL to query.
    :param expected_status_code: The expected HTTP status code.
    :param expected_body: The expected response text, None will not compare.
    :param HTTPS_verify: Should we verify the HTTPS server.
    :param client_cert_path: Filesystem path to a file with the client private
                             key and certificate.
    :param CA_certs_path: Filesystem path to a file containing CA certificates
                          to use for HTTPS validation.
    :param request_interval: Time, in seconds, to timeout a request.
    :param request_timeout: The maximum time, in seconds, to attempt requests.
                            Failed validation of expected results does not
                            result in a retry.
    :raises InvalidHttpSuccessCode: The expected_status_code did not match.
    :raises InvalidHTTPResponseBody: The response body did not match the
                                     expected content.
    :raises TimeoutException: The request timed out.
    :returns: None
    """
    with requests.Session() as session:
        session_kwargs = {}
        if not HTTPS_verify:
            session_kwargs['verify'] = False
        if CA_certs_path:
            session_kwargs['verify'] = CA_certs_path
        if client_cert_path:
            session_kwargs['cert'] = client_cert_path
        session_kwargs['timeout'] = request_interval
        start = time.time()
        while time.time() - start < request_timeout:
            try:
                response = session.get(URL, **session_kwargs)
                if response.status_code != expected_status_code:
                    raise exceptions.InvalidHttpSuccessCode(
                        '{0} is not the expected code {1}'.format(
                            response.status_code, expected_status_code))
                if expected_body and response.text != expected_body:
                    details = '{} does not match expected {}'.format(
                        response.text, expected_body)
                    raise exceptions.InvalidHTTPResponseBody(resp_body=details)
                return
            except requests.exceptions.Timeout:
                # Don't sleep as we have already waited the interval.
                LOG.info('Request for {} timed out. Retrying.'.format(URL))
            except (exceptions.InvalidHttpSuccessCode,
                    exceptions.InvalidHTTPResponseBody,
                    requests.exceptions.SSLError):
                raise
            except Exception as e:
                LOG.info('Validate URL got exception: {0}. '
                         'Retrying.'.format(e))
                time.sleep(request_interval)
        raise exceptions.TimeoutException()