Пример #1
0
def call_moto(context: RequestContext, include_response_metadata=False) -> ServiceResponse:
    """
    Call moto with the given request context and receive a parsed ServiceResponse.

    :param context: the request context
    :param include_response_metadata: whether to include botocore's "ResponseMetadata" attribute
    :return: a serialized AWS ServiceResponse (same as boto3 would return)
    """
    status, headers, content = dispatch_to_moto(context)

    operation_model = context.operation
    response_dict = {  # this is what botocore.endpoint.convert_to_response_dict normally does
        "headers": dict(headers.items()),  # boto doesn't like werkzeug headers
        "status_code": status,
        "body": to_bytes(content),
        "context": {
            "operation_name": operation_model.name,
        },
    }

    parser = create_parser(context.service.protocol)
    response = parser.parse(response_dict, operation_model.output_shape)

    if status >= 301:
        error = response["Error"]
        raise CommonServiceException(
            code=error.get("Code", "UnknownError"),
            status_code=status,
            message=error.get("Message", ""),
        )

    if not include_response_metadata:
        response.pop("ResponseMetadata", None)

    return response
Пример #2
0
def test_query_protocol_custom_error_serialization():
    exception = CommonServiceException("InvalidParameterValue",
                                       "Parameter x was invalid!")
    _botocore_error_serializer_integration_test("sqs", "SendMessage",
                                                exception,
                                                "InvalidParameterValue", 400,
                                                "Parameter x was invalid!")
Пример #3
0
def test_restjson_none_serialization():
    parameters = {
        "FunctionName": "test-name",
        "VpcConfig": {
            "SubnetIds": None,
            "SecurityGroupIds": [None],
            "VpcId": "123"
        },
        "TracingConfig": None,
        "DeadLetterConfig": {},
    }
    expected = {
        "FunctionName": "test-name",
        "VpcConfig": {
            "SecurityGroupIds": [],
            "VpcId": "123"
        },
        "DeadLetterConfig": {},
    }
    _botocore_serializer_integration_test("lambda",
                                          "CreateFunction",
                                          parameters,
                                          status_code=201,
                                          expected_response_content=expected)
    exception = CommonServiceException("CodeVerificationFailedException", None)
    _botocore_error_serializer_integration_test(
        "lambda",
        "CreateFunction",
        exception,
        "CodeVerificationFailedException",
        400,
        "",
    )
Пример #4
0
    def on_not_implemented_error(self,
                                 context: RequestContext) -> HttpResponse:
        """
        Called by invoke if either the dispatch table did not contain an entry for the operation, or the service
        provider raised a NotImplementedError
        :param context: the request context
        :return: an HttpResponse object
        """
        operation = context.operation
        serializer = self.serializer

        action_name = operation.name
        service_name = operation.service_model.service_name
        message = f"API action '{action_name}' for service '{service_name}' " f"not yet implemented"
        LOG.info(message)
        error = CommonServiceException("InternalFailure",
                                       message,
                                       status_code=501)
        # record event
        analytics.log.event("services_notimplemented",
                            payload={
                                "s": service_name,
                                "a": action_name
                            })
        return serializer.serialize_error_to_response(error, operation)
Пример #5
0
def test_restxml_none_serialization():
    # Structure = None
    _botocore_serializer_integration_test("route53",
                                          "ListHostedZonesByName", {},
                                          expected_response_content={})
    # Structure Value = None
    parameters = {"HostedZones": None}
    _botocore_serializer_integration_test("route53",
                                          "ListHostedZonesByName",
                                          parameters,
                                          expected_response_content={})
    # List Value = None
    parameters = {"HostedZones": [None]}
    expected = {"HostedZones": []}
    _botocore_serializer_integration_test("route53",
                                          "ListHostedZonesByName",
                                          parameters,
                                          expected_response_content=expected)
    # Exception without a message
    exception = CommonServiceException("NoSuchKeySigningKey", None)
    _botocore_error_serializer_integration_test(
        "route53",
        "DeleteKeySigningKey",
        exception,
        "NoSuchKeySigningKey",
        400,
        "",
    )
Пример #6
0
def call_moto(context: RequestContext) -> ServiceResponse:
    """
    Call moto with the given request context and receive a parsed ServiceResponse.

    :param context: the request context
    :return: a serialized AWS ServiceResponse (same as boto3 would return)
    """
    status, headers, content = dispatch_to_moto(context)

    operation_model = context.operation
    response_dict = {  # this is what botocore.endpoint.convert_to_response_dict normally does
        "headers": headers,
        "status_code": status,
        "body": to_bytes(content),
        "context": {
            "operation_name": operation_model.name,
        },
    }

    parser = create_parser(context.service.protocol)
    response = parser.parse(response_dict, operation_model.output_shape)

    if status >= 301:
        error = response["Error"]
        raise CommonServiceException(
            code=error.get("Code", "UnknownError"),
            status_code=status,
            message=error.get("Message", ""),
        )

    return response
Пример #7
0
def test_ec2_protocol_custom_error_serialization():
    exception = CommonServiceException("IdempotentParameterMismatch",
                                       "Different payload, same token?!")
    _botocore_error_serializer_integration_test(
        "ec2",
        "StartInstances",
        exception,
        "IdempotentParameterMismatch",
        400,
        "Different payload, same token?!",
    )
Пример #8
0
def test_restjson_protocol_custom_error_serialization():
    exception = CommonServiceException(
        "APIAccessCensorship",
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
        status_code=451,
    )
    _botocore_error_serializer_integration_test(
        "xray",
        "UpdateSamplingRule",
        exception,
        "APIAccessCensorship",
        451,
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
    )
Пример #9
0
def test_json_protocol_custom_error_serialization():
    exception = CommonServiceException(
        "APIAccessCensorship",
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
        status_code=451,
    )
    _botocore_error_serializer_integration_test(
        "cognito-idp",
        "CreateUserPool",
        exception,
        "APIAccessCensorship",
        451,
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
    )
Пример #10
0
def test_restxml_protocol_custom_error_serialization():
    exception = CommonServiceException(
        "APIAccessCensorship",
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
        status_code=451,
    )
    _botocore_error_serializer_integration_test(
        "cloudfront",
        "CreateCloudFrontOriginAccessIdentity",
        exception,
        "APIAccessCensorship",
        451,
        "You shall not access this API! Sincerely, your friendly neighbourhood firefighter.",
    )
Пример #11
0
    def _assert_permission(self, context: RequestContext, queue: SqsQueue):
        action = context.operation.name
        account_id = context.account_id

        if account_id == queue.owner:
            return

        for permission in queue.permissions:
            if permission.account_id != account_id:
                continue
            if permission.action == "*":
                return
            if permission.action == action:
                return

        raise CommonServiceException("AccessDeniedException", "Not allowed")
Пример #12
0
def dispatch_to_moto(context: RequestContext) -> MotoResponse:
    """
    Internal method to dispatch the request to moto without changing moto's dispatcher output.
    :param context: the request context
    :return: the response from moto
    """
    service = context.service
    request = context.request

    # this is where we skip the HTTP roundtrip between the moto server and the boto client
    dispatch = get_dispatcher(service.service_name, request.path)

    try:
        return dispatch(request, request.url, request.headers)
    except RESTError as e:
        raise CommonServiceException(e.error_type, e.message, status_code=e.code) from e
Пример #13
0
    def invoke(self, context: RequestContext) -> HttpResponse:
        if context.operation and context.service_request:
            # if the parsed request is already set in the context, re-use them
            operation, instance = context.operation, context.service_request
        else:
            # otherwise parse the incoming HTTPRequest
            operation, instance = self.parser.parse(context.request)
            context.operation = operation

        serializer = self.serializer

        try:
            # Find the operation's handler in the dispatch table
            if operation.name not in self.dispatch_table:
                LOG.warning(
                    "missing entry in dispatch table for %s.%s",
                    self.service.service_name,
                    operation.name,
                )
                raise NotImplementedError
            handler = self.dispatch_table[operation.name]

            # Call the appropriate handler
            result = handler(context, instance) or dict()
            # Serialize result dict to an HTTPResponse and return it
            return serializer.serialize_to_response(result, operation)
        except ServiceException as e:
            return serializer.serialize_error_to_response(e, operation)
        except NotImplementedError:
            action_name = operation.name
            service_name = operation.service_model.service_name
            message = (
                f"API action '{action_name}' for service '{service_name}' "
                f"not yet implemented")
            LOG.info(message)
            error = CommonServiceException("InternalFailure",
                                           message,
                                           status_code=501)

            # record event
            analytics.log.event("services_notimplemented",
                                payload={
                                    "s": service_name,
                                    "a": action_name
                                })

            return serializer.serialize_error_to_response(error, operation)
Пример #14
0
def handle_request(request: Request, region: str) -> Response:
    if request.is_json:
        # TODO: the response should be sent as JSON response
        raise NotImplementedError

    try:
        response, operation = try_call_sqs(request, region)
        del response["ResponseMetadata"]
        return serializer.serialize_to_response(response, operation)
    except UnknownOperationException:
        return Response("<UnknownOperationException/>", 404)
    except CommonServiceException as e:
        # use a dummy operation for the serialization to work
        op = service.operation_model(service.operation_names[0])
        return serializer.serialize_error_to_response(e, op)
    except Exception as e:
        LOG.exception("exception")
        op = service.operation_model(service.operation_names[0])
        return serializer.serialize_error_to_response(
            CommonServiceException(
                "InternalError", f"An internal error ocurred: {e}", status_code=500
            ),
            op,
        )
Пример #15
0
 def delete_queue(_context: RequestContext, _request: ServiceRequest):
     raise CommonServiceException("NonExistentQueue", "No such queue")