diff --git a/examples/2016-10-31/lambda_edge/README.md b/examples/2016-10-31/lambda_edge/README.md index 5d8e9a6ee7..b0f9521932 100644 --- a/examples/2016-10-31/lambda_edge/README.md +++ b/examples/2016-10-31/lambda_edge/README.md @@ -17,6 +17,23 @@ LambdaEdgeFunctionSample: AutoPublishAlias: live ``` +This also uses `ProvisionedConcurrencyConfig` setting on the lambda function Alias created by AutoPublishAlias: + +```yaml +LambdaEdgeFunctionSample: + Type: AWS::Serverless::Function + Properties: + CodeUri: src/ + Runtime: nodejs6.10 + Handler: index.handler + Role: !GetAtt LambdaEdgeFunctionRole.Arn + Timeout: 5 + # More info at https://github.com/awslabs/serverless-application-model/blob/master/docs/safe_lambda_deployments.rst + AutoPublishAlias: live + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: !If [AliasProvisionedConcurrencyEnabled, !Ref ProvisionedConcurrency, !Ref 'AWS::NoValue'] +``` + We must also create a custom IAM Role which allows `lambda.amazonaws.com` and `edgelambda.amazonaws.com` services to assume the role and execute the function. ```yaml diff --git a/examples/2016-10-31/lambda_edge/template.yaml b/examples/2016-10-31/lambda_edge/template.yaml index 3ae1fe61cd..25cd68aa0d 100644 --- a/examples/2016-10-31/lambda_edge/template.yaml +++ b/examples/2016-10-31/lambda_edge/template.yaml @@ -1,6 +1,24 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample SAM configuration for Lambda@Edge to ease deployment and further updates +Parameters: + + ProvisionedConcurrency: + Type: String + Default: 10 + EnableAliasProvisionedConcurrency: + Type: String + AllowedValues: + - true + - false + Default: true + +Globals: + + Function: + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: !If [AliasProvisionedConcurrencyEnabled, !Ref ProvisionedConcurrency, !Ref 'AWS::NoValue'] + Resources: CFDistribution: diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index bac6c206fe..9eb549af38 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = '1.17.0' +__version__ = '1.18.0' diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index c4e7de5148..10c4d68847 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -50,7 +50,8 @@ class LambdaAlias(Resource): 'Description': PropertyType(False, is_str()), 'Name': PropertyType(False, is_str()), 'FunctionName': PropertyType(True, one_of(is_str(), is_type(dict))), - 'FunctionVersion': PropertyType(True, one_of(is_str(), is_type(dict))) + 'FunctionVersion': PropertyType(True, one_of(is_str(), is_type(dict))), + 'ProvisionedConcurrencyConfig': PropertyType(False, is_type(dict)) } runtime_attrs = { diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index f2f56e7943..781636375a 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -55,7 +55,8 @@ class SamFunction(SamResourceMacro): # Intrinsic functions in value of Alias property are not supported, yet 'AutoPublishAlias': PropertyType(False, one_of(is_str())), - 'VersionDescription': PropertyType(False, is_str()) + 'VersionDescription': PropertyType(False, is_str()), + 'ProvisionedConcurrencyConfig': PropertyType(False, is_type(dict)), } event_resolver = ResourceTypeResolver(samtranslator.model.eventsources, samtranslator.model.eventsources.pull, samtranslator.model.eventsources.push, @@ -96,6 +97,11 @@ def to_cloudformation(self, **kwargs): lambda_function = self._construct_lambda_function() resources.append(lambda_function) + if self.ProvisionedConcurrencyConfig: + if not self.AutoPublishAlias: + raise InvalidResourceException(self.logical_id, "To set ProvisionedConcurrencyConfig " + "AutoPublishALias must be defined on the function") + lambda_alias = None if self.AutoPublishAlias: alias_name = self._get_resolved_alias_name("AutoPublishAlias", self.AutoPublishAlias, intrinsics_resolver) @@ -415,6 +421,8 @@ def _construct_alias(self, name, function, version): alias.Name = name alias.FunctionName = function.get_runtime_attr('name') alias.FunctionVersion = version.get_runtime_attr("version") + if self.ProvisionedConcurrencyConfig: + alias.ProvisionedConcurrencyConfig = self.ProvisionedConcurrencyConfig return alias diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 41cb9fc265..d3e371e87a 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -36,7 +36,8 @@ class Globals(object): "Layers", "DeploymentPreference", "PermissionsBoundary", - "ReservedConcurrentExecutions" + "ReservedConcurrentExecutions", + "ProvisionedConcurrencyConfig" ], # Everything except diff --git a/tests/translator/input/error_function_with_no_alias_provisioned_concurrency.yaml b/tests/translator/input/error_function_with_no_alias_provisioned_concurrency.yaml new file mode 100644 index 0000000000..92f1d07c7e --- /dev/null +++ b/tests/translator/input/error_function_with_no_alias_provisioned_concurrency.yaml @@ -0,0 +1,25 @@ +Parameters: + FnName: + Type: String + ProvisionedConcurrency: + Type: String + Default: 10 + EnableAliasProvisionedConcurrency: + Type: String + AllowedValues: + - true + - false + Default: true +Conditions: + AliasProvisionedConcurrencyEnabled: !Equals [!Ref EnableAliasProvisionedConcurrency, true] +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + DeploymentPreference: + Type: Linear10PercentEvery3Minutes + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: !If [AliasProvisionedConcurrencyEnabled, ProvisionedConcurrentExecutions: !Ref ProvisionedConcurrency, !Ref 'AWS::NoValue'] diff --git a/tests/translator/input/function_with_deployment_preference.yaml b/tests/translator/input/function_with_deployment_preference.yaml index 19eaa94311..c0d4e44c1c 100644 --- a/tests/translator/input/function_with_deployment_preference.yaml +++ b/tests/translator/input/function_with_deployment_preference.yaml @@ -1,3 +1,17 @@ +Parameters: + FnName: + Type: String + ProvisionedConcurrency: + Type: String + Default: 10 + EnableAliasProvisionedConcurrency: + Type: String + AllowedValues: + - true + - false + Default: true +Conditions: + AliasProvisionedConcurrencyEnabled: !Equals [!Ref EnableAliasProvisionedConcurrency, true] Resources: MinimalFunction: Type: 'AWS::Serverless::Function' @@ -7,4 +21,6 @@ Resources: Runtime: python2.7 AutoPublishAlias: live DeploymentPreference: - Type: Linear10PercentEvery3Minutes \ No newline at end of file + Type: Linear10PercentEvery3Minutes + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: !If [AliasProvisionedConcurrencyEnabled, !Ref ProvisionedConcurrency, !Ref 'AWS::NoValue'] diff --git a/tests/translator/output/aws-cn/function_with_deployment_preference.json b/tests/translator/output/aws-cn/function_with_deployment_preference.json index d610572865..5c5a9fe34d 100644 --- a/tests/translator/output/aws-cn/function_with_deployment_preference.json +++ b/tests/translator/output/aws-cn/function_with_deployment_preference.json @@ -1,4 +1,31 @@ { + "Conditions": { + "AliasProvisionedConcurrencyEnabled": { + "Fn::Equals": [ + { + "Ref": "EnableAliasProvisionedConcurrency" + }, + true + ] + } + }, + "Parameters": { + "EnableAliasProvisionedConcurrency": { + "Default": true, + "Type": "String", + "AllowedValues": [ + true, + false + ] + }, + "FnName": { + "Type": "String" + }, + "ProvisionedConcurrency": { + "Default": 10, + "Type": "String" + } + }, "Resources": { "MinimalFunctionDeploymentGroup": { "Type": "AWS::CodeDeploy::DeploymentGroup", @@ -61,11 +88,11 @@ "MinimalFunction": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "hello.handler", "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "hello.zip" }, - "Handler": "hello.handler", "Role": { "Fn::GetAtt": [ "MinimalFunctionRole", @@ -133,17 +160,30 @@ } }, "Properties": { + "Name": "live", "FunctionVersion": { "Fn::GetAtt": [ "MinimalFunctionVersion640128d35d", "Version" ] }, + "ProvisionedConcurrencyConfig": { + "ProvisionedConcurrentExecutions": { + "Fn::If": [ + "AliasProvisionedConcurrencyEnabled", + { + "Ref": "ProvisionedConcurrency" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "FunctionName": { "Ref": "MinimalFunction" - }, - "Name": "live" + } } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/function_with_deployment_preference.json b/tests/translator/output/aws-us-gov/function_with_deployment_preference.json index a16ba0a1d8..8146beb5ce 100644 --- a/tests/translator/output/aws-us-gov/function_with_deployment_preference.json +++ b/tests/translator/output/aws-us-gov/function_with_deployment_preference.json @@ -1,4 +1,31 @@ { + "Conditions": { + "AliasProvisionedConcurrencyEnabled": { + "Fn::Equals": [ + { + "Ref": "EnableAliasProvisionedConcurrency" + }, + true + ] + } + }, + "Parameters": { + "EnableAliasProvisionedConcurrency": { + "Default": true, + "Type": "String", + "AllowedValues": [ + true, + false + ] + }, + "FnName": { + "Type": "String" + }, + "ProvisionedConcurrency": { + "Default": 10, + "Type": "String" + } + }, "Resources": { "MinimalFunctionDeploymentGroup": { "Type": "AWS::CodeDeploy::DeploymentGroup", @@ -61,11 +88,11 @@ "MinimalFunction": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "hello.handler", "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "hello.zip" }, - "Handler": "hello.handler", "Role": { "Fn::GetAtt": [ "MinimalFunctionRole", @@ -133,16 +160,29 @@ } }, "Properties": { + "Name": "live", "FunctionVersion": { "Fn::GetAtt": [ "MinimalFunctionVersion640128d35d", "Version" ] }, + "ProvisionedConcurrencyConfig": { + "ProvisionedConcurrentExecutions": { + "Fn::If": [ + "AliasProvisionedConcurrencyEnabled", + { + "Ref": "ProvisionedConcurrency" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "FunctionName": { "Ref": "MinimalFunction" - }, - "Name": "live" + } } } } diff --git a/tests/translator/output/error_function_with_no_alias_provisioned_concurrency.json b/tests/translator/output/error_function_with_no_alias_provisioned_concurrency.json new file mode 100644 index 0000000000..1e5d1559e9 --- /dev/null +++ b/tests/translator/output/error_function_with_no_alias_provisioned_concurrency.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [MinimalFunction] is invalid. To set ProvisionedConcurrencyConfig AutoPublishALias must be defined on the function" + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MinimalFunction] is invalid. To set ProvisionedConcurrencyConfig AutoPublishALias must be defined on the function" +} \ 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 c814d640a1..b84f45e787 100644 --- a/tests/translator/output/error_globals_unsupported_property.json +++ b/tests/translator/output/error_globals_unsupported_property.json @@ -1,8 +1,8 @@ { "errors": [ { - "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']" + "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']" } ], - "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']" + "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']" } diff --git a/tests/translator/output/function_with_deployment_preference.json b/tests/translator/output/function_with_deployment_preference.json index 75ba695243..26589f9e06 100644 --- a/tests/translator/output/function_with_deployment_preference.json +++ b/tests/translator/output/function_with_deployment_preference.json @@ -1,4 +1,31 @@ { + "Conditions": { + "AliasProvisionedConcurrencyEnabled": { + "Fn::Equals": [ + { + "Ref": "EnableAliasProvisionedConcurrency" + }, + true + ] + } + }, + "Parameters": { + "EnableAliasProvisionedConcurrency": { + "Default": true, + "Type": "String", + "AllowedValues": [ + true, + false + ] + }, + "FnName": { + "Type": "String" + }, + "ProvisionedConcurrency": { + "Default": 10, + "Type": "String" + } + }, "Resources": { "MinimalFunctionDeploymentGroup": { "Type": "AWS::CodeDeploy::DeploymentGroup", @@ -61,11 +88,11 @@ "MinimalFunction": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "hello.handler", "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "hello.zip" }, - "Handler": "hello.handler", "Role": { "Fn::GetAtt": [ "MinimalFunctionRole", @@ -133,16 +160,29 @@ } }, "Properties": { + "Name": "live", "FunctionVersion": { "Fn::GetAtt": [ "MinimalFunctionVersion640128d35d", "Version" ] }, + "ProvisionedConcurrencyConfig": { + "ProvisionedConcurrentExecutions": { + "Fn::If": [ + "AliasProvisionedConcurrencyEnabled", + { + "Ref": "ProvisionedConcurrency" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "FunctionName": { "Ref": "MinimalFunction" - }, - "Name": "live" + } } } } diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index ea6b87d95c..2e2b72fa45 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -542,7 +542,8 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw 'error_function_with_invalid_policy_statement', 'error_function_with_invalid_condition_name', 'error_invalid_document_empty_semantic_version', - 'error_api_with_invalid_open_api_version_type' + 'error_api_with_invalid_open_api_version_type', + 'error_function_with_no_alias_provisioned_concurrency' ]) @patch('boto3.session.Session.region_name', 'ap-southeast-1') @patch('samtranslator.plugins.application.serverless_app_plugin.ServerlessAppPlugin._sar_service_call', mock_sar_service_call) diff --git a/versions/2016-10-31.md b/versions/2016-10-31.md index 84bcbcdac9..c43ebbd6f8 100644 --- a/versions/2016-10-31.md +++ b/versions/2016-10-31.md @@ -126,6 +126,7 @@ Layers | list of `string` | List of LayerVersion ARNs that should be used by thi AutoPublishAlias | `string` | Name of the Alias. Read [AutoPublishAlias Guide](../docs/safe_lambda_deployments.rst#instant-traffic-shifting-using-lambda-aliases) for how it works VersionDescription | `string` | A string that specifies the Description field which will be added on the new lambda version ReservedConcurrentExecutions | `integer` | The maximum of concurrent executions you want to reserve for the function. For more information see [AWS Documentation on managing concurrency](https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html) +ProvisionedConcurrencyConfig | [ProvisionedConcurrencyConfig Object](#provisioned-concurrency-config-object) | Configure provisioned capacity for a number of concurrent executions on Lambda Alias property. ##### Return values @@ -755,6 +756,15 @@ Properties: Type: AlexaSkill ``` +#### Provisioned Concurrency Config object + +The object describing provisioned concurrency settings on a Lambda Alias + +##### Properties +Property Name | Type | Description +---|:---:|--- +ProvisionedConcurrentExecutions | `string` | Number of concurrent executions to be provisioned for the Lambda function. Required parameter. + #### Primary key object The object describing the properties of a primary key.