Skip to content

Commit 34ac03e

Browse files
praneetapkeetonian
authored andcommitted
feat: support for lambda event destinations (#1321)
1 parent a93bbff commit 34ac03e

32 files changed

+3105
-13
lines changed

docs/cloudformation_compatibility.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ DeploymentPreference All
6363
Layers All
6464
AutoPublishAlias Ref of a CloudFormation Parameter Alias resources created by SAM uses a LocicalId <FunctionLogicalId+AliasName>. So SAM either needs a string for alias name, or a Ref to template Parameter that SAM can resolve into a string.
6565
ReservedConcurrentExecutions All
66+
EventInvokeConfig All
6667
============================ ================================== ========================
6768

6869
Events Properties

docs/globals.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Currently, the following resources and properties are being supported:
6969
DeploymentPreference:
7070
PermissionsBoundary:
7171
ReservedConcurrentExecutions:
72+
EventInvokeConfig:
7273
7374
Api:
7475
# Properties of AWS::Serverless::Api
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# API Gateway + Lambda REQUEST Authorizer Example
2+
3+
This example shows you how to configure Event Invoke Config on a function.
4+
5+
## Running the example
6+
7+
Replace the Destination Arns for SQS, SNS, EventBridge with valid arns.
8+
Deploy the example into your account:
9+
10+
```bash
11+
$ sam deploy \
12+
--template-file /path_to_template/packaged-template.yaml \
13+
--stack-name my-new-stack \
14+
--capabilities CAPABILITY_IAM
15+
```
16+
17+
## Additional resources
18+
19+
- https://aws.amazon.com/blogs/compute/introducing-aws-lambda-destinations/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
exports.handler = function(event, context, callback) {
2+
var event_received_at = new Date().toISOString();
3+
console.log('Event received at: ' + event_received_at);
4+
console.log('Received event:', JSON.stringify(event, null, 2));
5+
6+
if (event.Success) {
7+
console.log("Success");
8+
context.callbackWaitsForEmptyEventLoop = false;
9+
callback(null);
10+
} else {
11+
console.log("Failure");
12+
context.callbackWaitsForEmptyEventLoop = false;
13+
callback(new Error("Failure from event, Success = false, I am failing!"), 'Destination Function Error Thrown');
14+
}
15+
};
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: Lambda Event Destinations
4+
Parameters:
5+
SQSArn:
6+
Type: String
7+
Default: my-sqs-arn
8+
UseExistingQueue:
9+
Type: String
10+
AllowedValues:
11+
- true
12+
- false
13+
Default: true
14+
CreateSNSTopic:
15+
Type: String
16+
AllowedValues:
17+
- true
18+
- false
19+
Default: true
20+
Conditions:
21+
QueueCreationDisabled: !Equals [!Ref UseExistingQueue, true]
22+
TopicCreationEnabled: !Equals [!Ref CreateSNSTopic, true]
23+
24+
Resources:
25+
EventDestinationLambda:
26+
Type: AWS::Serverless::Function
27+
Properties:
28+
EventInvokeConfig:
29+
MaximumEventAgeInSeconds: 70
30+
MaximumRetryAttempts: 1
31+
DestinationConfig:
32+
OnSuccess:
33+
Type: Lambda
34+
# If the type is Lambda/EventBridge, Destination property is required.
35+
Destination: !GetAtt DestinationLambda.Arn
36+
OnFailure:
37+
# SQS and SNS will get auto-created if the Destination property is not specified or is AWS::NoValue
38+
Type: SQS
39+
CodeUri: ./src/
40+
Handler: index.handler
41+
Runtime: nodejs10.x
42+
MemorySize: 1024
43+
44+
EventDestinationSQSSNS:
45+
Type: AWS::Serverless::Function
46+
Properties:
47+
EventInvokeConfig:
48+
MaximumEventAgeInSeconds: 70
49+
MaximumRetryAttempts: 1
50+
DestinationConfig:
51+
OnSuccess:
52+
Type: SQS
53+
Destination: !If [QueueCreationDisabled, !Ref SQSArn, !Ref 'AWS::NoValue']
54+
OnFailure:
55+
Type: SNS
56+
Destination: !If [TopicCreationEnabled, !Ref 'AWS::NoValue', 'SOME-SNS-ARN']
57+
CodeUri: ./src/
58+
Handler: index.handler
59+
Runtime: nodejs10.x
60+
MemorySize: 1024
61+
62+
DestinationLambda:
63+
Type: AWS::Serverless::Function
64+
Properties:
65+
InlineCode: |
66+
exports.handler = async (event) => {
67+
const response = {
68+
statusCode: 200,
69+
body: JSON.stringify('Hello from Lambda!'),
70+
};
71+
return response;
72+
};
73+
Handler: index.handler
74+
Runtime: nodejs10.x
75+
MemorySize: 1024
76+
SNSSubscription:
77+
Type: AWS::SNS::Subscription
78+
Condition: TopicCreationEnabled
79+
Properties:
80+
81+
Protocol: email
82+
# Refer to the auto-created SNS topic using <function-logical-id>.DestinationTopic
83+
TopicArn: !Ref EventDestinationSQSSNS.DestinationTopic

samtranslator/model/iam.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,31 @@ def sns_publish_role_policy(cls, topic_arn, logical_id):
9191
}
9292
}
9393
return document
94+
95+
@classmethod
96+
def event_bus_put_events_role_policy(cls, event_bus_arn, logical_id):
97+
document = {
98+
'PolicyName': logical_id + 'EventBridgePolicy',
99+
'PolicyDocument': {
100+
'Statement': [{
101+
'Action': 'events:PutEvents',
102+
'Effect': 'Allow',
103+
'Resource': event_bus_arn
104+
}]
105+
}
106+
}
107+
return document
108+
109+
@classmethod
110+
def lambda_invoke_function_role_policy(cls, function_arn, logical_id):
111+
document = {
112+
'PolicyName': logical_id + 'LambdaPolicy',
113+
'PolicyDocument': {
114+
'Statement': [{
115+
'Action': 'lambda:InvokeFunction',
116+
'Effect': 'Allow',
117+
'Resource': function_arn
118+
}]
119+
}
120+
}
121+
return document

samtranslator/model/intrinsics.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,24 @@ def fnOr(argument_list):
2020
return {'Fn::Or': argument_list}
2121

2222

23-
def make_conditional(condition, data):
23+
def fnAnd(argument_list):
24+
return {'Fn::And': argument_list}
25+
26+
27+
def make_conditional(condition, true_data, false_data={'Ref': 'AWS::NoValue'}):
2428
return {
2529
'Fn::If': [
2630
condition,
27-
data,
28-
{'Ref': 'AWS::NoValue'}
31+
true_data,
32+
false_data
33+
]
34+
}
35+
36+
37+
def make_not_conditional(condition):
38+
return {
39+
'Fn::Not': [
40+
{'Condition': condition}
2941
]
3042
}
3143

@@ -44,6 +56,12 @@ def make_or_condition(conditions_list):
4456
return condition
4557

4658

59+
def make_and_condition(conditions_list):
60+
and_list = make_condition_or_list(conditions_list)
61+
condition = fnAnd(and_list)
62+
return condition
63+
64+
4765
def calculate_number_of_conditions(conditions_length, max_conditions):
4866
"""
4967
Every condition can hold up to max_conditions, which (as of writing this) is 10.

samtranslator/model/lambda_.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ class LambdaPermission(Resource):
9292
}
9393

9494

95+
class LambdaEventInvokeConfig(Resource):
96+
resource_type = 'AWS::Lambda::EventInvokeConfig'
97+
property_types = {
98+
'DestinationConfig': PropertyType(False, is_type(dict)),
99+
'FunctionName': PropertyType(True, is_str()),
100+
'MaximumEventAgeInSeconds': PropertyType(False, is_type(int)),
101+
'MaximumRetryAttempts': PropertyType(False, is_type(int)),
102+
'Qualifier': PropertyType(True, is_str())
103+
}
104+
105+
95106
class LambdaLayerVersion(Resource):
96107
""" Lambda layer version resource
97108
"""

0 commit comments

Comments
 (0)