Exemple #1
0
def send_event_to_target(arn, event, target_attributes=None, asynchronous=True):
    region = arn.split(':')[3]

    if ':lambda:' in arn:
        from localstack.services.awslambda import lambda_api
        lambda_api.run_lambda(func_arn=arn, event=event, context={}, asynchronous=asynchronous)

    elif ':sns:' in arn:
        sns_client = connect_to_service('sns', region_name=region)
        sns_client.publish(TopicArn=arn, Message=json.dumps(event))

    elif ':sqs:' in arn:
        sqs_client = connect_to_service('sqs', region_name=region)
        queue_url = get_sqs_queue_url(arn)
        msg_group_id = dict_utils.get_safe(target_attributes, '$.SqsParameters.MessageGroupId')
        kwargs = {'MessageGroupId': msg_group_id} if msg_group_id else {}
        sqs_client.send_message(QueueUrl=queue_url, MessageBody=json.dumps(event), **kwargs)

    elif ':states:' in arn:
        stepfunctions_client = connect_to_service('stepfunctions', region_name=region)
        stepfunctions_client.start_execution(stateMachineArn=arn, input=json.dumps(event))

    elif ':firehose:' in arn:
        delivery_stream_name = firehose_name(arn)
        firehose_client = connect_to_service('firehose', region_name=region)
        firehose_client.put_record(
            DeliveryStreamName=delivery_stream_name,
            Record={'Data': to_bytes(json.dumps(event))})

    elif ':events:' in arn:
        bus_name = arn.split(':')[-1].split('/')[-1]
        events_client = connect_to_service('events', region_name=region)
        events_client.put_events(
            Entries=[{
                'EventBusName': bus_name,
                'Source': event.get('source'),
                'DetailType': event.get('detail-type'),
                'Detail': event.get('detail')
            }]
        )

    elif ':kinesis:' in arn:
        partition_key_path = dict_utils.get_safe(
            target_attributes,
            '$.KinesisParameters.PartitionKeyPath',
            default_value='$.id'
        )

        stream_name = arn.split('/')[-1]
        partition_key = dict_utils.get_safe(event, partition_key_path, event['id'])
        kinesis_client = connect_to_service('kinesis', region_name=region)

        kinesis_client.put_record(
            StreamName=stream_name,
            Data=to_bytes(json.dumps(event)),
            PartitionKey=partition_key
        )

    else:
        LOG.warning('Unsupported Events rule target ARN: "%s"' % arn)
    def func(*args):
        rule_name = data.get('Name')
        client = aws_stack.connect_to_service('events')
        targets = client.list_targets_by_rule(Rule=rule_name)['Targets']
        if targets:
            LOG.debug(
                'Notifying %s targets in response to triggered Events rule %s'
                % (len(targets), rule_name))
        for target in targets:
            arn = target.get('Arn')
            event = json.loads(target.get('Input') or '{}')

            if ':lambda:' in arn:
                lambda_api.run_lambda(event=event, context={}, func_arn=arn)

            elif ':sns:' in arn:
                sns_client = aws_stack.connect_to_service('sns')
                sns_client.publish(TopicArn=arn, Message=json.dumps(event))

            elif ':sqs:' in arn:
                sqs_client = aws_stack.connect_to_service('sqs')
                queue_url = aws_stack.get_sqs_queue_url(arn)
                sqs_client.send_message(QueueUrl=queue_url,
                                        MessageBody=json.dumps(event))

            elif ':states' in arn:
                stepfunctions_client = aws_stack.connect_to_service(
                    'stepfunctions')
                stepfunctions_client.start_execution(stateMachineArn=arn,
                                                     input=json.dumps(event))

            else:
                LOG.info('Unsupported Events rule target ARN "%s"' % arn)
Exemple #3
0
def send_event_to_target(arn, event, target_attributes=None):
    if ':lambda:' in arn:
        from localstack.services.awslambda import lambda_api
        lambda_api.run_lambda(event=event, context={}, func_arn=arn)

    elif ':sns:' in arn:
        sns_client = connect_to_service('sns')
        sns_client.publish(TopicArn=arn, Message=json.dumps(event))

    elif ':sqs:' in arn:
        sqs_client = connect_to_service('sqs')
        queue_url = get_sqs_queue_url(arn)

        msg_group_id = (target_attributes or {}).get('MessageGroupId')
        kwargs = {'MessageGroupId': msg_group_id} if msg_group_id else {}
        sqs_client.send_message(QueueUrl=queue_url,
                                MessageBody=json.dumps(event),
                                **kwargs)

    elif ':states' in arn:
        stepfunctions_client = connect_to_service('stepfunctions')
        stepfunctions_client.start_execution(stateMachineArn=arn,
                                             input=json.dumps(event))

    else:
        LOG.info('Unsupported Events rule target ARN "%s"' % arn)
def forward_to_lambda(records):
    for record in records:
        sources = lambda_api.get_event_sources(source_arn=record['eventSourceARN'])
        event = {
            'Records': [record]
        }
        for src in sources:
            lambda_api.run_lambda(event=event, context={}, func_arn=src['FunctionArn'])
Exemple #5
0
def forward_to_lambda(records):
    for record in records:
        sources = lambda_api.get_event_sources(source_arn=record['eventSourceARN'])
        event = {
            'Records': [record]
        }
        for src in sources:
            lambda_api.run_lambda(event=event, context={}, func_arn=src['FunctionArn'])
def forward_to_lambda(records):
    for record in records:
        sources = lambda_api.get_event_sources(source_arn=record['eventSourceARN'])
        event = {
            'Records': [record]
        }
        for src in sources:
            if src.get('State') != 'Enabled':
                continue
            lambda_api.run_lambda(func_arn=src['FunctionArn'], event=event, context={},
                asynchronous=not config.SYNCHRONOUS_DYNAMODB_EVENTS)
Exemple #7
0
def forward_to_lambda(records):
    for record in records:
        sources = lambda_api.get_event_sources(
            source_arn=record["eventSourceARN"])
        event = {"Records": [record]}
        for src in sources:
            if src.get("State") != "Enabled":
                continue
            lambda_api.run_lambda(
                func_arn=src["FunctionArn"],
                event=event,
                context={},
                asynchronous=not config.SYNCHRONOUS_DYNAMODB_EVENTS,
            )
Exemple #8
0
 def func(*args):
     rule_name = data.get('Name')
     client = aws_stack.connect_to_service('events')
     targets = client.list_targets_by_rule(Rule=rule_name)['Targets']
     if targets:
         LOG.debug(
             'Notifying %s targets in response to triggered Events rule %s'
             % (len(targets), rule_name))
     for target in targets:
         arn = target.get('Arn')
         if ':lambda:' in arn:
             event = json.loads(target.get('Input') or '{}')
             lambda_api.run_lambda(event=event, context={}, func_arn=arn)
         else:
             LOG.info('Unsupported Events rule target ARN "%s"' % arn)
Exemple #9
0
    def _invoke_lambda(
        self, function_arn, payload, lock_discriminator, parallelization_factor
    ) -> Tuple[bool, int]:
        """
        invoke a given lambda function
        :returns: True if the invocation was successful (False otherwise) and the status code of the invocation result
        """
        if not config.SYNCHRONOUS_KINESIS_EVENTS:
            lambda_executors.LAMBDA_ASYNC_LOCKS.assure_lock_present(
                lock_discriminator, threading.BoundedSemaphore(parallelization_factor)
            )
        else:
            lock_discriminator = None

        result = run_lambda(
            func_arn=function_arn,
            event=payload,
            context={},
            asynchronous=not config.SYNCHRONOUS_KINESIS_EVENTS,
            lock_discriminator=lock_discriminator,
        )
        if isinstance(result, InvocationResult):
            status_code = getattr(result.result, "status_code", 0)
            if status_code >= 400:
                return False, status_code
            return True, status_code
        return False, 500
Exemple #10
0
def send_event_to_target(arn, event):
    if ':lambda:' in arn:
        from localstack.services.awslambda import lambda_api
        lambda_api.run_lambda(event=event, context={}, func_arn=arn)

    elif ':sns:' in arn:
        sns_client = connect_to_service('sns')
        sns_client.publish(TopicArn=arn, Message=json.dumps(event))

    elif ':sqs:' in arn:
        sqs_client = connect_to_service('sqs')
        queue_url = get_sqs_queue_url(arn)
        sqs_client.send_message(QueueUrl=queue_url, MessageBody=json.dumps(event))

    elif ':states' in arn:
        stepfunctions_client = connect_to_service('stepfunctions')
        stepfunctions_client.start_execution(stateMachineArn=arn, input=json.dumps(event))

    else:
        LOG.info('Unsupported Events rule target ARN "%s"' % arn)
Exemple #11
0
def send_event_to_target(arn, event, target_attributes=None, asynchronous=True):
    region = arn.split(':')[3]

    if ':lambda:' in arn:
        from localstack.services.awslambda import lambda_api
        lambda_api.run_lambda(func_arn=arn, event=event, context={}, asynchronous=asynchronous)

    elif ':sns:' in arn:
        sns_client = connect_to_service('sns', region_name=region)
        sns_client.publish(TopicArn=arn, Message=json.dumps(event))

    elif ':sqs:' in arn:
        sqs_client = connect_to_service('sqs', region_name=region)
        queue_url = get_sqs_queue_url(arn)
        msg_group_id = dict_utils.get_safe(target_attributes, '$.SqsParameters.MessageGroupId')
        kwargs = {'MessageGroupId': msg_group_id} if msg_group_id else {}
        sqs_client.send_message(QueueUrl=queue_url, MessageBody=json.dumps(event), **kwargs)

    elif ':states:' in arn:
        stepfunctions_client = connect_to_service('stepfunctions', region_name=region)
        stepfunctions_client.start_execution(stateMachineArn=arn, input=json.dumps(event))

    elif ':firehose:' in arn:
        delivery_stream_name = firehose_name(arn)
        firehose_client = connect_to_service('firehose', region_name=region)
        firehose_client.put_record(
            DeliveryStreamName=delivery_stream_name,
            Record={'Data': to_bytes(json.dumps(event))})

    elif ':events:' in arn:
        events_client = connect_to_service('events', region_name=region)
        target_name = arn.split(':')[-1].split('/')[-1]
        if ':destination/' in arn:
            destination = events_client.describe_api_destination(Name=target_name)
            method = destination.get('HttpMethod', 'GET')
            endpoint = destination.get('InvocationEndpoint')
            state = destination.get('ApiDestinationState') or 'ACTIVE'
            LOG.debug('Calling EventBridge API destination (state "%s"): %s %s' % (state, method, endpoint))
            result = requests.request(method=method, url=endpoint, data=json.dumps(event or {}))
            if result.status_code >= 400:
                LOG.debug('Received code %s forwarding events: %s %s' % (result.status_code, method, endpoint))
        else:
            events_client.put_events(
                Entries=[{
                    'EventBusName': target_name,
                    'Source': event.get('source'),
                    'DetailType': event.get('detail-type'),
                    'Detail': event.get('detail')
                }]
            )

    elif ':kinesis:' in arn:
        partition_key_path = dict_utils.get_safe(
            target_attributes,
            '$.KinesisParameters.PartitionKeyPath',
            default_value='$.id'
        )

        stream_name = arn.split('/')[-1]
        partition_key = dict_utils.get_safe(event, partition_key_path, event['id'])
        kinesis_client = connect_to_service('kinesis', region_name=region)

        kinesis_client.put_record(
            StreamName=stream_name,
            Data=to_bytes(json.dumps(event)),
            PartitionKey=partition_key
        )

    else:
        LOG.warning('Unsupported Events rule target ARN: "%s"' % arn)
Exemple #12
0
def send_event_to_lambda(event, arn):
    run_lambda(event=event, context={}, func_arn=arn, asynchronous=True)
Exemple #13
0
def send_event_to_target(
    target_arn: str,
    event: Dict,
    target_attributes: Dict = None,
    asynchronous: bool = True,
    target: Dict = {},
):
    region = target_arn.split(":")[3]

    if ":lambda:" in target_arn:
        from localstack.services.awslambda import lambda_api

        lambda_api.run_lambda(func_arn=target_arn,
                              event=event,
                              context={},
                              asynchronous=asynchronous)

    elif ":sns:" in target_arn:
        sns_client = connect_to_service("sns", region_name=region)
        sns_client.publish(TopicArn=target_arn, Message=json.dumps(event))

    elif ":sqs:" in target_arn:
        sqs_client = connect_to_service("sqs", region_name=region)
        queue_url = get_sqs_queue_url(target_arn)
        msg_group_id = dict_utils.get_safe(target_attributes,
                                           "$.SqsParameters.MessageGroupId")
        kwargs = {"MessageGroupId": msg_group_id} if msg_group_id else {}
        sqs_client.send_message(QueueUrl=queue_url,
                                MessageBody=json.dumps(event),
                                **kwargs)

    elif ":states:" in target_arn:
        stepfunctions_client = connect_to_service("stepfunctions",
                                                  region_name=region)
        stepfunctions_client.start_execution(stateMachineArn=target_arn,
                                             input=json.dumps(event))

    elif ":firehose:" in target_arn:
        delivery_stream_name = firehose_name(target_arn)
        firehose_client = connect_to_service("firehose", region_name=region)
        firehose_client.put_record(
            DeliveryStreamName=delivery_stream_name,
            Record={"Data": to_bytes(json.dumps(event))},
        )

    elif ":events:" in target_arn:
        if ":api-destination/" in target_arn or ":destination/" in target_arn:
            send_event_to_api_destination(target_arn, event,
                                          target.get("HttpParameters"))

        else:
            events_client = connect_to_service("events", region_name=region)
            eventbus_name = target_arn.split(":")[-1].split("/")[-1]
            events_client.put_events(
                Entries=[{
                    "EventBusName": eventbus_name,
                    "Source": event.get("source"),
                    "DetailType": event.get("detail-type"),
                    "Detail": event.get("detail"),
                }])

    elif ":kinesis:" in target_arn:
        partition_key_path = dict_utils.get_safe(
            target_attributes,
            "$.KinesisParameters.PartitionKeyPath",
            default_value="$.id",
        )

        stream_name = target_arn.split("/")[-1]
        partition_key = dict_utils.get_safe(event, partition_key_path,
                                            event["id"])
        kinesis_client = connect_to_service("kinesis", region_name=region)

        kinesis_client.put_record(
            StreamName=stream_name,
            Data=to_bytes(json.dumps(event)),
            PartitionKey=partition_key,
        )

    elif ":logs:" in target_arn:
        log_group_name = target_arn.split(":")[-1]
        logs_client = connect_to_service("logs", region_name=region)
        log_stream_name = str(uuid.uuid4())
        logs_client.create_log_stream(logGroupName=log_group_name,
                                      logStreamName=log_stream_name)
        logs_client.put_log_events(
            logGroupName=log_group_name,
            logStreamName=log_stream_name,
            logEvents=[{
                "timestamp": now_utc(millis=True),
                "message": json.dumps(event)
            }],
        )
    else:
        LOG.warning('Unsupported Events rule target ARN: "%s"', target_arn)
    def _send_event_to_lambda(self, queue_arn, queue_url, lambda_arn, messages,
                              region):
        def delete_messages(result,
                            func_arn,
                            event,
                            error=None,
                            dlq_sent=None,
                            **kwargs):
            if error and not dlq_sent:
                # Skip deleting messages from the queue in case of processing errors AND if
                # the message has not yet been sent to a dead letter queue (DLQ).
                # We'll pick them up and retry next time they become available on the queue.
                return

            region_name = queue_arn.split(":")[3]
            sqs_client = aws_stack.connect_to_service("sqs",
                                                      region_name=region_name)
            entries = [{
                "Id": r["receiptHandle"],
                "ReceiptHandle": r["receiptHandle"]
            } for r in records]
            try:
                sqs_client.delete_message_batch(QueueUrl=queue_url,
                                                Entries=entries)
            except Exception as e:
                LOG.info(
                    "Unable to delete Lambda events from SQS queue " +
                    "(please check SQS visibility timeout settings): %s - %s" %
                    (entries, e))

        records = []
        for msg in messages:
            message_attrs = message_attributes_to_lower(
                msg.get("MessageAttributes"))
            records.append({
                "body":
                msg.get("Body", "MessageBody"),
                "receiptHandle":
                msg.get("ReceiptHandle"),
                "md5OfBody":
                msg.get("MD5OfBody") or msg.get("MD5OfMessageBody"),
                "eventSourceARN":
                queue_arn,
                "eventSource":
                lambda_executors.EVENT_SOURCE_SQS,
                "awsRegion":
                region,
                "messageId":
                msg["MessageId"],
                "attributes":
                msg.get("Attributes", {}),
                "messageAttributes":
                message_attrs,
                "md5OfMessageAttributes":
                msg.get("MD5OfMessageAttributes"),
                "sqs":
                True,
            })

        event = {"Records": records}

        # TODO implement retries, based on "RedrivePolicy.maxReceiveCount" in the queue settings
        res = run_lambda(
            func_arn=lambda_arn,
            event=event,
            context={},
            asynchronous=True,
            callback=delete_messages,
        )
        if isinstance(res, InvocationResult):
            status_code = getattr(res.result, "status_code", 0)
            if status_code >= 400:
                return False
        return True
Exemple #15
0
def send_event_to_lambda(event, arn):
    run_lambda(event=json.loads(event['Detail']),
               context={},
               func_arn=arn,
               asynchronous=True)
Exemple #16
0
def send_event_to_target(target_arn, event, target_attributes=None, asynchronous=True):
    region = target_arn.split(":")[3]

    if ":lambda:" in target_arn:
        from localstack.services.awslambda import lambda_api

        lambda_api.run_lambda(
            func_arn=target_arn, event=event, context={}, asynchronous=asynchronous
        )

    elif ":sns:" in target_arn:
        sns_client = connect_to_service("sns", region_name=region)
        sns_client.publish(TopicArn=target_arn, Message=json.dumps(event))

    elif ":sqs:" in target_arn:
        sqs_client = connect_to_service("sqs", region_name=region)
        queue_url = get_sqs_queue_url(target_arn)
        msg_group_id = dict_utils.get_safe(target_attributes, "$.SqsParameters.MessageGroupId")
        kwargs = {"MessageGroupId": msg_group_id} if msg_group_id else {}
        sqs_client.send_message(QueueUrl=queue_url, MessageBody=json.dumps(event), **kwargs)

    elif ":states:" in target_arn:
        stepfunctions_client = connect_to_service("stepfunctions", region_name=region)
        stepfunctions_client.start_execution(stateMachineArn=target_arn, input=json.dumps(event))

    elif ":firehose:" in target_arn:
        delivery_stream_name = firehose_name(target_arn)
        firehose_client = connect_to_service("firehose", region_name=region)
        firehose_client.put_record(
            DeliveryStreamName=delivery_stream_name,
            Record={"Data": to_bytes(json.dumps(event))},
        )

    elif ":events:" in target_arn:
        events_client = connect_to_service("events", region_name=region)
        if ":api-destination/" in target_arn:
            # API destination support
            # see https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html
            api_destination_name = target_arn.split(":")[-1].split("/")[
                1
            ]  # ...:api-destination/{name}/{uuid}
            destination = events_client.describe_api_destination(Name=api_destination_name)
            method = destination.get("HttpMethod", "GET")
            endpoint = destination.get("InvocationEndpoint")
            state = destination.get("ApiDestinationState") or "ACTIVE"
            LOG.debug(
                'Calling EventBridge API destination (state "%s"): %s %s'
                % (state, method, endpoint)
            )
            # TODO: support connection/auth (BASIC AUTH, API KEY, OAUTH)
            # connection_arn = destination.get("ConnectionArn")
            headers = {
                # default headers AWS sends with every api destination call
                "User-Agent": "Amazon/EventBridge/ApiDestinations",
                "Content-Type": "application/json; charset=utf-8",
                "Range": "bytes=0-1048575",
                "Accept-Encoding": "gzip,deflate",
                "Connection": "close",
            }
            # TODO: consider option to disable the actual network call to avoid unintended side effects
            # TODO: InvocationRateLimitPerSecond (needs some form of thread-safety, scoped to the api destination)
            result = requests.request(
                method=method, url=endpoint, data=json.dumps(event or {}), headers=headers
            )
            if result.status_code >= 400:
                LOG.debug(
                    "Received code %s forwarding events: %s %s"
                    % (result.status_code, method, endpoint)
                )
                if result.status_code == 429 or 500 <= result.status_code <= 600:
                    pass  # TODO: retry logic (only retry on 429 and 5xx response status)
        else:
            eventbus_name = target_arn.split(":")[-1].split("/")[-1]
            events_client.put_events(
                Entries=[
                    {
                        "EventBusName": eventbus_name,
                        "Source": event.get("source"),
                        "DetailType": event.get("detail-type"),
                        "Detail": event.get("detail"),
                    }
                ]
            )

    elif ":kinesis:" in target_arn:
        partition_key_path = dict_utils.get_safe(
            target_attributes,
            "$.KinesisParameters.PartitionKeyPath",
            default_value="$.id",
        )

        stream_name = target_arn.split("/")[-1]
        partition_key = dict_utils.get_safe(event, partition_key_path, event["id"])
        kinesis_client = connect_to_service("kinesis", region_name=region)

        kinesis_client.put_record(
            StreamName=stream_name,
            Data=to_bytes(json.dumps(event)),
            PartitionKey=partition_key,
        )

    else:
        LOG.warning('Unsupported Events rule target ARN: "%s"' % target_arn)