diff --git a/.cfnlintrc.yaml b/.cfnlintrc.yaml index 8b0d3c164..7d236593a 100644 --- a/.cfnlintrc.yaml +++ b/.cfnlintrc.yaml @@ -137,6 +137,7 @@ ignore_templates: - tests/translator/output/**/function_with_intrinsics_resource_attribute.json # CFN now supports intrinsics in DeletionPolicy - tests/translator/output/**/function_with_snapstart.json # Snapstart intentionally not attached to a lambda version which causes lint issues - tests/translator/output/**/managed_policies_everything.json # intentionally contains wrong arns + - tests/translator/output/**/function_with_metrics_config.json ignore_checks: - E2531 # Deprecated runtime; not relevant for transform tests - E2533 # Another deprecated runtime; not relevant for transform tests diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index e70b96d07..1dd4da685 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.92.0" +__version__ = "1.93.0" diff --git a/samtranslator/internal/schema_source/aws_serverless_function.py b/samtranslator/internal/schema_source/aws_serverless_function.py index bd0740e55..aa607331c 100644 --- a/samtranslator/internal/schema_source/aws_serverless_function.py +++ b/samtranslator/internal/schema_source/aws_serverless_function.py @@ -105,12 +105,12 @@ class DeadLetterQueue(BaseModel): class EventInvokeOnFailure(BaseModel): Destination: Optional[SamIntrinsicable[str]] = eventinvokeonfailure("Destination") - Type: Optional[Literal["SQS", "SNS", "Lambda", "EventBridge"]] = eventinvokeonfailure("Type") + Type: Optional[Literal["SQS", "SNS", "Lambda", "EventBridge", "S3Bucket"]] = eventinvokeonfailure("Type") class EventInvokeOnSuccess(BaseModel): Destination: Optional[SamIntrinsicable[str]] = eventinvokeonsuccess("Destination") - Type: Optional[Literal["SQS", "SNS", "Lambda", "EventBridge"]] = eventinvokeonsuccess("Type") + Type: Optional[Literal["SQS", "SNS", "Lambda", "EventBridge", "S3Bucket"]] = eventinvokeonsuccess("Type") class EventInvokeDestinationConfig(BaseModel): @@ -178,6 +178,7 @@ class KinesisEventProperties(BaseModel): StartingPositionTimestamp: Optional[PassThroughProp] = kinesiseventproperties("StartingPositionTimestamp") Stream: PassThroughProp = kinesiseventproperties("Stream") TumblingWindowInSeconds: Optional[PassThroughProp] = kinesiseventproperties("TumblingWindowInSeconds") + MetricsConfig: Optional[PassThroughProp] class KinesisEvent(BaseModel): @@ -203,6 +204,7 @@ class DynamoDBEventProperties(BaseModel): StartingPositionTimestamp: Optional[PassThroughProp] = dynamodbeventproperties("StartingPositionTimestamp") Stream: PassThroughProp = dynamodbeventproperties("Stream") TumblingWindowInSeconds: Optional[PassThroughProp] = dynamodbeventproperties("TumblingWindowInSeconds") + MetricsConfig: Optional[PassThroughProp] class DynamoDBEvent(BaseModel): @@ -241,6 +243,7 @@ class SQSEventProperties(BaseModel): MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = sqseventproperties("MaximumBatchingWindowInSeconds") Queue: PassThroughProp = sqseventproperties("Queue") ScalingConfig: Optional[PassThroughProp] # Update docs when live + MetricsConfig: Optional[PassThroughProp] class SQSEvent(BaseModel): diff --git a/samtranslator/model/eventsources/pull.py b/samtranslator/model/eventsources/pull.py index b5298771c..4b1bfe828 100644 --- a/samtranslator/model/eventsources/pull.py +++ b/samtranslator/model/eventsources/pull.py @@ -55,6 +55,7 @@ class PullEventSource(ResourceMacro, metaclass=ABCMeta): "KmsKeyArn": PassThroughProperty(False), "ConsumerGroupId": PropertyType(False, IS_STR), "ScalingConfig": PropertyType(False, IS_DICT), + "MetricsConfig": PropertyType(False, IS_DICT), } BatchSize: Optional[Intrinsicable[int]] @@ -78,6 +79,7 @@ class PullEventSource(ResourceMacro, metaclass=ABCMeta): KmsKeyArn: Optional[Intrinsicable[str]] ConsumerGroupId: Optional[Intrinsicable[str]] ScalingConfig: Optional[Dict[str, Any]] + MetricsConfig: Optional[Dict[str, Any]] @abstractmethod def get_policy_arn(self) -> Optional[str]: @@ -145,6 +147,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P lambda_eventsourcemapping.FilterCriteria = self.FilterCriteria lambda_eventsourcemapping.KmsKeyArn = self.KmsKeyArn lambda_eventsourcemapping.ScalingConfig = self.ScalingConfig + lambda_eventsourcemapping.MetricsConfig = self.MetricsConfig self._validate_filter_criteria() if self.KafkaBootstrapServers: diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index e76809735..fe98dd3d4 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -122,6 +122,7 @@ class LambdaEventSourceMapping(Resource): "AmazonManagedKafkaEventSourceConfig": GeneratedProperty(), "SelfManagedKafkaEventSourceConfig": GeneratedProperty(), "ScalingConfig": GeneratedProperty(), + "MetricsConfig": GeneratedProperty(), } runtime_attrs = {"name": lambda self: ref(self.logical_id)} diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index b5c1e21d4..29d55f348 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1,4 +1,4 @@ -""" SAM macro definitions """ +""" SAM macro definitions """ import copy from contextlib import suppress @@ -441,7 +441,7 @@ def _validate_and_inject_resource( ARN property, so to handle conditional ifs we have to inject if conditions in the auto created SQS/SNS resources as well as in the policy documents. """ - accepted_types_list = ["SQS", "SNS", "EventBridge", "Lambda"] + accepted_types_list = ["SQS", "SNS", "EventBridge", "Lambda", "S3Bucket"] auto_inject_list = ["SQS", "SNS"] resource: Optional[Union[SNSTopic, SQSQueue]] = None policy = {} @@ -632,6 +632,8 @@ def _add_event_invoke_managed_policy( return IAMRolePolicies.event_bus_put_events_role_policy(dest_arn, logical_id) if _type == "Lambda": return IAMRolePolicies.lambda_invoke_function_role_policy(dest_arn, logical_id) + if _type == "S3Bucket": + return IAMRolePolicies.s3_send_event_payload_role_policy(dest_arn, logical_id) return {} def _construct_role( diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index a27469ed6..0eae3d70c 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -274755,6 +274755,9 @@ "markdownDescription": "The maximum number of times to retry when the function returns an error\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumRetryAttempts`](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumretryattempts) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumRetryAttempts" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "ParallelizationFactor": { "allOf": [ { @@ -274990,7 +274993,8 @@ "SQS", "SNS", "Lambda", - "EventBridge" + "EventBridge", + "S3Bucket" ], "markdownDescription": "Type of the resource referenced in the destination\\. Supported types are `SQS`, `SNS`, `Lambda`, and `EventBridge`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: If the type is SQS/SNS and the `Destination` property is left blank, then the SQS/SNS resource is auto generated by SAM\\. To reference the resource, use `.DestinationQueue` for SQS or `.DestinationTopic` for SNS\\. If the type is Lambda/EventBridge, `Destination` is required\\.", "title": "Type", @@ -275020,7 +275024,8 @@ "SQS", "SNS", "Lambda", - "EventBridge" + "EventBridge", + "S3Bucket" ], "markdownDescription": "Type of the resource referenced in the destination\\. Supported types are `SQS`, `SNS`, `Lambda`, and `EventBridge`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: If the type is SQS/SNS and the `Destination` property is left blank, then the SQS/SNS resource is auto generated by SAM\\. To reference the resource, use `.DestinationQueue` for SQS or `.DestinationTopic` for SNS\\. If the type is Lambda/EventBridge, `Destination` is required\\.", "title": "Type", @@ -275502,6 +275507,9 @@ "markdownDescription": "The maximum number of times to retry when the function returns an error\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumRetryAttempts`](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumretryattempts) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumRetryAttempts" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "ParallelizationFactor": { "allOf": [ { @@ -276759,6 +276767,9 @@ "markdownDescription": "The maximum amount of time, in seconds, to gather records before invoking the function\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumBatchingWindowInSeconds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumbatchingwindowinseconds) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumBatchingWindowInSeconds" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Queue": { "allOf": [ { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 632b7dad9..375e5bc38 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -1004,6 +1004,9 @@ "markdownDescription": "The maximum number of times to retry when the function returns an error\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumRetryAttempts`](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumretryattempts) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumRetryAttempts" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "ParallelizationFactor": { "allOf": [ { @@ -1257,7 +1260,8 @@ "SQS", "SNS", "Lambda", - "EventBridge" + "EventBridge", + "S3Bucket" ], "markdownDescription": "Type of the resource referenced in the destination\\. Supported types are `SQS`, `SNS`, `Lambda`, and `EventBridge`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: If the type is SQS/SNS and the `Destination` property is left blank, then the SQS/SNS resource is auto generated by SAM\\. To reference the resource, use `.DestinationQueue` for SQS or `.DestinationTopic` for SNS\\. If the type is Lambda/EventBridge, `Destination` is required\\.", "title": "Type", @@ -1287,7 +1291,8 @@ "SQS", "SNS", "Lambda", - "EventBridge" + "EventBridge", + "S3Bucket" ], "markdownDescription": "Type of the resource referenced in the destination\\. Supported types are `SQS`, `SNS`, `Lambda`, and `EventBridge`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: If the type is SQS/SNS and the `Destination` property is left blank, then the SQS/SNS resource is auto generated by SAM\\. To reference the resource, use `.DestinationQueue` for SQS or `.DestinationTopic` for SNS\\. If the type is Lambda/EventBridge, `Destination` is required\\.", "title": "Type", @@ -1769,6 +1774,9 @@ "markdownDescription": "The maximum number of times to retry when the function returns an error\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumRetryAttempts`](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumretryattempts) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumRetryAttempts" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "ParallelizationFactor": { "allOf": [ { @@ -2957,6 +2965,9 @@ "markdownDescription": "The maximum amount of time, in seconds, to gather records before invoking the function\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaximumBatchingWindowInSeconds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumbatchingwindowinseconds) property of an `AWS::Lambda::EventSourceMapping` resource\\.", "title": "MaximumBatchingWindowInSeconds" }, + "MetricsConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Queue": { "allOf": [ { diff --git a/tests/translator/input/function_with_event_dest_s3_bucket.yaml b/tests/translator/input/function_with_event_dest_s3_bucket.yaml new file mode 100644 index 000000000..b7f6aa128 --- /dev/null +++ b/tests/translator/input/function_with_event_dest_s3_bucket.yaml @@ -0,0 +1,77 @@ +Parameters: + S3BucketArn1: + Type: String + Default: arn:aws:s3::123456789012:my_bucket-1 + S3BucketArn2: + Type: String + Default: arn:aws:s3::123456789012:my_bucket-2 +Globals: + Function: + AutoPublishAlias: live + EventInvokeConfig: + MaximumEventAgeInSeconds: 70 + MaximumRetryAttempts: 1 + DestinationConfig: + OnSuccess: + Type: S3Bucket + Destination: !Ref S3BucketArn1 + OnFailure: + Type: S3Bucket + Destination: !Ref S3BucketArn2 + +Resources: + MyTestFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = function(event, context, callback) { + var event_received_at = new Date().toISOString(); + console.log('Event received at: ' + event_received_at); + console.log('Received event:', JSON.stringify(event, null, 2)); + + if (event.Success) { + console.log("Success"); + context.callbackWaitsForEmptyEventLoop = false; + callback(null); + } else { + console.log("Failure"); + context.callbackWaitsForEmptyEventLoop = false; + callback(new Error("Failure from event, Success = false, I am failing!"), 'Destination Function Error Thrown'); + } + }; + Handler: index.handler + Runtime: nodejs12.x + MemorySize: 1024 + + MyTestFunction2: + Type: AWS::Serverless::Function + Properties: + EventInvokeConfig: + MaximumEventAgeInSeconds: 70 + MaximumRetryAttempts: 1 + DestinationConfig: + OnSuccess: + Type: S3Bucket + Destination: arn:aws:s3::123456789012:my_bucket-3 + OnFailure: + Type: S3Bucket + Destination: arn:aws:s3::123456789012:my_bucket-4 + InlineCode: | + exports.handler = function(event, context, callback) { + var event_received_at = new Date().toISOString(); + console.log('Event received at: ' + event_received_at); + console.log('Received event:', JSON.stringify(event, null, 2)); + + if (event.Success) { + console.log("Success"); + context.callbackWaitsForEmptyEventLoop = false; + callback(null); + } else { + console.log("Failure"); + context.callbackWaitsForEmptyEventLoop = false; + callback(new Error("Failure from event, Success = false, I am failing!"), 'Destination Function Error Thrown'); + } + }; + Handler: index.handler + Runtime: nodejs12.x + MemorySize: 1024 diff --git a/tests/translator/input/function_with_metrics_config.yaml b/tests/translator/input/function_with_metrics_config.yaml new file mode 100644 index 000000000..e1b581efb --- /dev/null +++ b/tests/translator/input/function_with_metrics_config.yaml @@ -0,0 +1,58 @@ +Resources: + FilteredEventsFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/metricsConfig.zip + Handler: index.handler + Runtime: nodejs16.x + Events: + KinesisStream: + Type: Kinesis + Properties: + Stream: !GetAtt KinesisStream.Arn + StartingPosition: LATEST + MetricsConfig: + Metrics: + - EventCount + FilterCriteria: + Filters: + - Pattern: '{"name": "value"}' + - Pattern: '{"name2": "value2"}' + DynamoDBStreamEvent: + Type: DynamoDB + Properties: + Stream: !GetAtt DynamoDBTable.StreamArn + StartingPosition: TRIM_HORIZON + MetricsConfig: + Metrics: [] + FilterCriteria: + Filters: [] + MySqsQueue: + Type: SQS + Properties: + Queue: !GetAtt MySqsQueue.Arn + MetricsConfig: + Metrics: + - EventCount + FilterCriteria: + Filters: + - Pattern: '{"name": "value"}' + + KinesisStream: + Type: AWS::Kinesis::Stream + Properties: + ShardCount: 1 + + DynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + AttributeDefinitions: + - AttributeName: id + AttributeType: S + BillingMode: PAY_PER_REQUEST + KeySchema: + - AttributeName: id + KeyType: HASH + + MySqsQueue: + Type: AWS::SQS::Queue diff --git a/tests/translator/output/aws-cn/function_with_event_dest_s3_bucket.json b/tests/translator/output/aws-cn/function_with_event_dest_s3_bucket.json new file mode 100644 index 000000000..8a9c1a268 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_event_dest_s3_bucket.json @@ -0,0 +1,316 @@ +{ + "Parameters": { + "S3BucketArn1": { + "Default": "arn:aws:s3::123456789012:my_bucket-1", + "Type": "String" + }, + "S3BucketArn2": { + "Default": "arn:aws:s3::123456789012:my_bucket-2", + "Type": "String" + } + }, + "Resources": { + "MyTestFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunction2Role", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2Aliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunction2Versiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunction2EventInvokeConfig": { + "DependsOn": [ + "MyTestFunction2Aliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-4" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-3" + } + }, + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunction2Role": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-3", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-3" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-4", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-4" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunction2Versiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyTestFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunctionVersiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunctionEventInvokeConfig": { + "DependsOn": [ + "MyTestFunctionAliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-2" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-1" + } + }, + "FunctionName": { + "Ref": "MyTestFunction" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-1", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-1" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-2", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-2" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunctionVersiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_metrics_config.json b/tests/translator/output/aws-cn/function_with_metrics_config.json new file mode 100644 index 000000000..eae07b130 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_metrics_config.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "DynamoDBTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + }, + "Type": "AWS::DynamoDB::Table" + }, + "FilteredEventsFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "metricsConfig.zip" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "FilteredEventsFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "FilteredEventsFunctionDynamoDBStreamEvent": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "DynamoDBTable", + "StreamArn" + ] + }, + "FilterCriteria": { + "Filters": [] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [] + }, + "StartingPosition": "TRIM_HORIZON" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionKinesisStream": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "KinesisStream", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + }, + { + "Pattern": "{\"name2\": \"value2\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + }, + "StartingPosition": "LATEST" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionMySqsQueue": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "MySqsQueue", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole", + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole", + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "KinesisStream": { + "Properties": { + "ShardCount": 1 + }, + "Type": "AWS::Kinesis::Stream" + }, + "MySqsQueue": { + "Type": "AWS::SQS::Queue" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_event_dest_s3_bucket.json b/tests/translator/output/aws-us-gov/function_with_event_dest_s3_bucket.json new file mode 100644 index 000000000..e7350f2c6 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_event_dest_s3_bucket.json @@ -0,0 +1,316 @@ +{ + "Parameters": { + "S3BucketArn1": { + "Default": "arn:aws:s3::123456789012:my_bucket-1", + "Type": "String" + }, + "S3BucketArn2": { + "Default": "arn:aws:s3::123456789012:my_bucket-2", + "Type": "String" + } + }, + "Resources": { + "MyTestFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunction2Role", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2Aliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunction2Versiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunction2EventInvokeConfig": { + "DependsOn": [ + "MyTestFunction2Aliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-4" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-3" + } + }, + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunction2Role": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-3", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-3" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-4", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-4" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunction2Versiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyTestFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunctionVersiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunctionEventInvokeConfig": { + "DependsOn": [ + "MyTestFunctionAliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-2" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-1" + } + }, + "FunctionName": { + "Ref": "MyTestFunction" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-1", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-1" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-2", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-2" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunctionVersiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_metrics_config.json b/tests/translator/output/aws-us-gov/function_with_metrics_config.json new file mode 100644 index 000000000..30b9b857e --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_metrics_config.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "DynamoDBTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + }, + "Type": "AWS::DynamoDB::Table" + }, + "FilteredEventsFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "metricsConfig.zip" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "FilteredEventsFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "FilteredEventsFunctionDynamoDBStreamEvent": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "DynamoDBTable", + "StreamArn" + ] + }, + "FilterCriteria": { + "Filters": [] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [] + }, + "StartingPosition": "TRIM_HORIZON" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionKinesisStream": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "KinesisStream", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + }, + { + "Pattern": "{\"name2\": \"value2\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + }, + "StartingPosition": "LATEST" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionMySqsQueue": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "MySqsQueue", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole", + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole", + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "KinesisStream": { + "Properties": { + "ShardCount": 1 + }, + "Type": "AWS::Kinesis::Stream" + }, + "MySqsQueue": { + "Type": "AWS::SQS::Queue" + } + } +} diff --git a/tests/translator/output/error_function_with_event_dest_type.json b/tests/translator/output/error_function_with_event_dest_type.json index 41e6a6901..6ffb2708d 100644 --- a/tests/translator/output/error_function_with_event_dest_type.json +++ b/tests/translator/output/error_function_with_event_dest_type.json @@ -3,10 +3,10 @@ "Invalid Serverless Application Specification document. ", "Number of errors found: 3. ", "Resource with id [MyTestFunction] is invalid. ", - "'Type: blah' must be one of ['SQS', 'SNS', 'EventBridge', 'Lambda'] Resource with id [MyTestFunctionInvalidDestinationConfigOnSuccessType] is invalid. ", + "'Type: blah' must be one of ['SQS', 'SNS', 'EventBridge', 'Lambda', 'S3Bucket'] Resource with id [MyTestFunctionInvalidDestinationConfigOnSuccessType] is invalid. ", "Property 'EventInvokeConfig.DestinationConfig.OnSuccess' should be a map. ", "Resource with id [MyTestFunctionInvalidDestinationConfigType] is invalid. ", "Property 'EventInvokeConfig.DestinationConfig' should be a map." ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 3. Resource with id [MyTestFunction] is invalid. 'Type: blah' must be one of ['SQS', 'SNS', 'EventBridge', 'Lambda'] Resource with id [MyTestFunctionInvalidDestinationConfigOnSuccessType] is invalid. Property 'EventInvokeConfig.DestinationConfig.OnSuccess' should be a map. Resource with id [MyTestFunctionInvalidDestinationConfigType] is invalid. Property 'EventInvokeConfig.DestinationConfig' should be a map." + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 3. Resource with id [MyTestFunction] is invalid. 'Type: blah' must be one of ['SQS', 'SNS', 'EventBridge', 'Lambda', 'S3Bucket'] Resource with id [MyTestFunctionInvalidDestinationConfigOnSuccessType] is invalid. Property 'EventInvokeConfig.DestinationConfig.OnSuccess' should be a map. Resource with id [MyTestFunctionInvalidDestinationConfigType] is invalid. Property 'EventInvokeConfig.DestinationConfig' should be a map." } diff --git a/tests/translator/output/function_with_event_dest_s3_bucket.json b/tests/translator/output/function_with_event_dest_s3_bucket.json new file mode 100644 index 000000000..1b1dd0a48 --- /dev/null +++ b/tests/translator/output/function_with_event_dest_s3_bucket.json @@ -0,0 +1,316 @@ +{ + "Parameters": { + "S3BucketArn1": { + "Default": "arn:aws:s3::123456789012:my_bucket-1", + "Type": "String" + }, + "S3BucketArn2": { + "Default": "arn:aws:s3::123456789012:my_bucket-2", + "Type": "String" + } + }, + "Resources": { + "MyTestFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, context, callback) {\n var event_received_at = new Date().toISOString();\n console.log('Event received at: ' + event_received_at);\n console.log('Received event:', JSON.stringify(event, null, 2));\n\n if (event.Success) {\n console.log(\"Success\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(null);\n } else {\n console.log(\"Failure\");\n context.callbackWaitsForEmptyEventLoop = false;\n callback(new Error(\"Failure from event, Success = false, I am failing!\"), 'Destination Function Error Thrown');\n }\n}; \n" + }, + "Handler": "index.handler", + "MemorySize": 1024, + "Role": { + "Fn::GetAtt": [ + "MyTestFunction2Role", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyTestFunction2Aliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunction2Versiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunction2EventInvokeConfig": { + "DependsOn": [ + "MyTestFunction2Aliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-4" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-3" + } + }, + "FunctionName": { + "Ref": "MyTestFunction2" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunction2Role": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-3", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-3" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-4", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-4" + } + ] + }, + "PolicyName": "MyTestFunction2EventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunction2Versiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction2" + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyTestFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyTestFunctionVersiondaf9da458d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MyTestFunctionEventInvokeConfig": { + "DependsOn": [ + "MyTestFunctionAliaslive" + ], + "Properties": { + "DestinationConfig": { + "OnFailure": { + "Destination": "arn:aws:s3::123456789012:my_bucket-2" + }, + "OnSuccess": { + "Destination": "arn:aws:s3::123456789012:my_bucket-1" + } + }, + "FunctionName": { + "Ref": "MyTestFunction" + }, + "MaximumEventAgeInSeconds": 70, + "MaximumRetryAttempts": 1, + "Qualifier": "live" + }, + "Type": "AWS::Lambda::EventInvokeConfig" + }, + "MyTestFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-1", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-1" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnSuccessS3Policy" + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "/", + [ + "arn:aws:s3::123456789012:my_bucket-2", + "*" + ] + ] + } + }, + { + "Action": "s3:ListBucket", + "Effect": "Allow", + "Resource": "arn:aws:s3::123456789012:my_bucket-2" + } + ] + }, + "PolicyName": "MyTestFunctionEventInvokeConfigOnFailureS3Policy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyTestFunctionVersiondaf9da458d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "MyTestFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/function_with_metrics_config.json b/tests/translator/output/function_with_metrics_config.json new file mode 100644 index 000000000..ed6521020 --- /dev/null +++ b/tests/translator/output/function_with_metrics_config.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "DynamoDBTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + }, + "Type": "AWS::DynamoDB::Table" + }, + "FilteredEventsFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "metricsConfig.zip" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "FilteredEventsFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "FilteredEventsFunctionDynamoDBStreamEvent": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "DynamoDBTable", + "StreamArn" + ] + }, + "FilterCriteria": { + "Filters": [] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [] + }, + "StartingPosition": "TRIM_HORIZON" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionKinesisStream": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "KinesisStream", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + }, + { + "Pattern": "{\"name2\": \"value2\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + }, + "StartingPosition": "LATEST" + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionMySqsQueue": { + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "MySqsQueue", + "Arn" + ] + }, + "FilterCriteria": { + "Filters": [ + { + "Pattern": "{\"name\": \"value\"}" + } + ] + }, + "FunctionName": { + "Ref": "FilteredEventsFunction" + }, + "MetricsConfig": { + "Metrics": [ + "EventCount" + ] + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "FilteredEventsFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole", + "arn:aws:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole", + "arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "KinesisStream": { + "Properties": { + "ShardCount": 1 + }, + "Type": "AWS::Kinesis::Stream" + }, + "MySqsQueue": { + "Type": "AWS::SQS::Queue" + } + } +}