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)
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'])
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)
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, )
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)
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
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)
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)
def send_event_to_lambda(event, arn): run_lambda(event=event, context={}, func_arn=arn, asynchronous=True)
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
def send_event_to_lambda(event, arn): run_lambda(event=json.loads(event['Detail']), context={}, func_arn=arn, asynchronous=True)
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)