diff --git a/docs/globals.rst b/docs/globals.rst index 22cfc933d..30c78f308 100644 --- a/docs/globals.rst +++ b/docs/globals.rst @@ -71,6 +71,7 @@ Currently, the following resources and properties are being supported: ReservedConcurrentExecutions: EventInvokeConfig: Architectures: + EphemeralStorage: Api: # Properties of AWS::Serverless::Api diff --git a/integration/resources/expected/single/function_with_ephemeral_storage.json b/integration/resources/expected/single/function_with_ephemeral_storage.json new file mode 100644 index 000000000..5cc61a85c --- /dev/null +++ b/integration/resources/expected/single/function_with_ephemeral_storage.json @@ -0,0 +1,4 @@ +[ + { "LogicalResourceId":"MyLambdaFunction", "ResourceType":"AWS::Lambda::Function" }, + { "LogicalResourceId":"MyLambdaFunctionRole", "ResourceType":"AWS::IAM::Role" } + ] \ No newline at end of file diff --git a/integration/resources/templates/single/function_with_ephemeral_storage.yaml b/integration/resources/templates/single/function_with_ephemeral_storage.yaml new file mode 100644 index 000000000..39927accf --- /dev/null +++ b/integration/resources/templates/single/function_with_ephemeral_storage.yaml @@ -0,0 +1,17 @@ +Resources: + MyLambdaFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs12.x + CodeUri: ${codeuri} + MemorySize: 128 + EphemeralStorage: + Size: 1024 + Policies: + - AWSLambdaRole + - AmazonS3ReadOnlyAccess + Environment: + Variables: + Name: Value + Name2: Value2 \ No newline at end of file diff --git a/integration/single/test_basic_function.py b/integration/single/test_basic_function.py index 1b441a631..b6f2b394d 100644 --- a/integration/single/test_basic_function.py +++ b/integration/single/test_basic_function.py @@ -204,3 +204,22 @@ def test_basic_function_with_tracing(self): "PassThrough", "Expecting tracing config mode to be set to PassThrough.", ) + + @parameterized.expand( + [ + "single/function_with_ephemeral_storage", + ] + ) + def test_function_with_ephemeral_storage(self, file_name): + """ + Creates a basic function with ephemeral storage + """ + self.create_and_verify_stack(file_name) + + function_id = self.get_physical_id_by_logical_id("MyLambdaFunction") + + function_configuration_result = self.client_provider.lambda_client.get_function_configuration( + FunctionName=function_id + ) + + self.assertEqual(function_configuration_result.get("EphemeralStorage", {}).get("Size", 0), 1024) diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index eb012bb42..5f3948ed5 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.43.0" +__version__ = "1.44.0" diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index 0c822d640..bec1ed738 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -27,6 +27,7 @@ class LambdaFunction(Resource): "CodeSigningConfigArn": PropertyType(False, is_str()), "ImageConfig": PropertyType(False, is_type(dict)), "Architectures": PropertyType(False, list_of(one_of(is_str(), is_type(dict)))), + "EphemeralStorage": PropertyType(False, is_type(dict)), } runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")} diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 57efa747f..9b1cf9251 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -83,6 +83,7 @@ class SamFunction(SamResourceMacro): "ReservedConcurrentExecutions": PropertyType(False, any_type()), "Layers": PropertyType(False, list_of(one_of(is_str(), is_type(dict)))), "EventInvokeConfig": PropertyType(False, is_type(dict)), + "EphemeralStorage": PropertyType(False, is_type(dict)), # Intrinsic functions in value of Alias property are not supported, yet "AutoPublishAlias": PropertyType(False, one_of(is_str())), "AutoPublishCodeSha256": PropertyType(False, one_of(is_str())), @@ -426,6 +427,7 @@ def _construct_lambda_function(self): lambda_function.ImageConfig = self.ImageConfig lambda_function.PackageType = self.PackageType lambda_function.Architectures = self.Architectures + lambda_function.EphemeralStorage = self.EphemeralStorage if self.Tracing: lambda_function.TracingConfig = {"Mode": self.Tracing} diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 0b2680769..9da2183bb 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -42,6 +42,7 @@ class Globals(object): "FileSystemConfigs", "CodeSigningConfigArn", "Architectures", + "EphemeralStorage", ], # Everything except # DefinitionBody: because its hard to reason about merge of Swagger dictionaries diff --git a/tests/translator/input/function_with_ephemeral_storage.yaml b/tests/translator/input/function_with_ephemeral_storage.yaml new file mode 100644 index 000000000..97177a3c8 --- /dev/null +++ b/tests/translator/input/function_with_ephemeral_storage.yaml @@ -0,0 +1,20 @@ +Parameters: + EphemeralStorageSizeRef: + Type: Number +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + EphemeralStorage: + Size: 1024 + FunctionWithIntrinsicRef: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + EphemeralStorage: + Size: !Ref EphemeralStorageSizeRef \ No newline at end of file diff --git a/tests/translator/input/globals_for_function.yaml b/tests/translator/input/globals_for_function.yaml index bc3d802aa..2fc6da8d3 100644 --- a/tests/translator/input/globals_for_function.yaml +++ b/tests/translator/input/globals_for_function.yaml @@ -24,6 +24,8 @@ Globals: ReservedConcurrentExecutions: 50 Architectures: - x86_64 + EphemeralStorage: + Size: 1024 Resources: MinimalFunction: diff --git a/tests/translator/output/aws-cn/function_with_ephemeral_storage.json b/tests/translator/output/aws-cn/function_with_ephemeral_storage.json new file mode 100644 index 000000000..a8a252b0f --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_ephemeral_storage.json @@ -0,0 +1,123 @@ +{ + "Resources": { + "FunctionWithIntrinsicRef": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": { + "Ref": "EphemeralStorageSizeRef" + } + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithIntrinsicRefRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithIntrinsicRefRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": 1024 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + } + }, + "Parameters": { + "EphemeralStorageSizeRef": { + "Type": "Number" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/globals_for_function.json b/tests/translator/output/aws-cn/globals_for_function.json index dd8cad638..01050a770 100644 --- a/tests/translator/output/aws-cn/globals_for_function.json +++ b/tests/translator/output/aws-cn/globals_for_function.json @@ -84,6 +84,9 @@ ], "ReservedConcurrentExecutions": 100, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 512, "Environment": { "Variables": { @@ -190,6 +193,9 @@ ], "ReservedConcurrentExecutions": 50, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 1024, "Environment": { "Variables": { @@ -242,4 +248,4 @@ } } } -} +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_ephemeral_storage.json b/tests/translator/output/aws-us-gov/function_with_ephemeral_storage.json new file mode 100644 index 000000000..d634b0af0 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_ephemeral_storage.json @@ -0,0 +1,123 @@ +{ + "Resources": { + "FunctionWithIntrinsicRef": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": { + "Ref": "EphemeralStorageSizeRef" + } + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithIntrinsicRefRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithIntrinsicRefRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": 1024 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + } + }, + "Parameters": { + "EphemeralStorageSizeRef": { + "Type": "Number" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/globals_for_function.json b/tests/translator/output/aws-us-gov/globals_for_function.json index 49abeafa7..cfd77a3e9 100644 --- a/tests/translator/output/aws-us-gov/globals_for_function.json +++ b/tests/translator/output/aws-us-gov/globals_for_function.json @@ -84,6 +84,9 @@ ], "ReservedConcurrentExecutions": 100, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 512, "Environment": { "Variables": { @@ -190,6 +193,9 @@ ], "ReservedConcurrentExecutions": 50, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 1024, "Environment": { "Variables": { @@ -242,4 +248,4 @@ } } } -} +} \ No newline at end of file diff --git a/tests/translator/output/error_globals_unsupported_property.json b/tests/translator/output/error_globals_unsupported_property.json index 706b2aabd..ecd008031 100644 --- a/tests/translator/output/error_globals_unsupported_property.json +++ b/tests/translator/output/error_globals_unsupported_property.json @@ -4,5 +4,5 @@ "errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures']" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures']" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures', 'EphemeralStorage']" } \ No newline at end of file diff --git a/tests/translator/output/function_with_ephemeral_storage.json b/tests/translator/output/function_with_ephemeral_storage.json new file mode 100644 index 000000000..1ad81d462 --- /dev/null +++ b/tests/translator/output/function_with_ephemeral_storage.json @@ -0,0 +1,123 @@ +{ + "Resources": { + "FunctionWithIntrinsicRef": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": { + "Ref": "EphemeralStorageSizeRef" + } + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithIntrinsicRefRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithIntrinsicRefRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "EphemeralStorage": { + "Size": 1024 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + } + }, + "Parameters": { + "EphemeralStorageSizeRef": { + "Type": "Number" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/globals_for_function.json b/tests/translator/output/globals_for_function.json index f922869fb..65afb4677 100644 --- a/tests/translator/output/globals_for_function.json +++ b/tests/translator/output/globals_for_function.json @@ -84,6 +84,9 @@ ], "ReservedConcurrentExecutions": 100, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 512, "Environment": { "Variables": { @@ -190,6 +193,9 @@ ], "ReservedConcurrentExecutions": 50, "Architectures": ["x86_64"], + "EphemeralStorage": { + "Size": 1024 + }, "MemorySize": 1024, "Environment": { "Variables": { diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 936f31c95..e255a0216 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -355,6 +355,7 @@ class TestTranslatorEndToEnd(AbstractTestTranslator): "intrinsic_functions", "basic_function_with_tags", "depends_on", + "function_with_ephemeral_storage", "function_event_conditions", "function_with_dlq", "function_with_kmskeyarn",