diff --git a/.cfnlintrc.yaml b/.cfnlintrc.yaml index fee4c28be9..5fd8d0032a 100644 --- a/.cfnlintrc.yaml +++ b/.cfnlintrc.yaml @@ -144,6 +144,7 @@ ignore_templates: - tests/translator/output/**/function_with_metrics_config.json - tests/translator/output/**/function_with_self_managed_kafka_and_schema_registry.json # cfnlint is not updated to recognize the SchemaRegistryConfig property - tests/translator/output/**/function_with_msk_with_schema_registry_config.json # cfnlint is not updated to recognize the SchemaRegistryConfig property + - tests/translator/output/**/*capacity_provider*.json # TODO: Remove this once CFN updates - tests/translator/output/**/function_with_tenancy_config.json # cfnlint is not updated to recognize the TenancyConfig property - tests/translator/output/**/function_with_tenancy_and_api_event.json # cfnlint is not updated to recognize the TenancyConfig property - tests/translator/output/**/function_with_tenancy_and_httpapi_event.json # cfnlint is not updated to recognize the TenancyConfig property diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index 1e7114c2e0..3ad358e222 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.103.0" +__version__ = "1.104.0" diff --git a/samtranslator/internal/schema_source/aws_serverless_capacity_provider.py b/samtranslator/internal/schema_source/aws_serverless_capacity_provider.py new file mode 100644 index 0000000000..8d97a501bb --- /dev/null +++ b/samtranslator/internal/schema_source/aws_serverless_capacity_provider.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +from typing import List, Literal, Optional + +from samtranslator.internal.schema_source.common import ( + BaseModel, + DictStrAny, + PassThroughProp, + ResourceAttributes, + SamIntrinsicable, + get_prop, +) + +PROPERTIES_STEM = "sam-resource-capacityprovider" +VPC_CONFIG_STEM = "sam-property-capacityprovider-vpcconfig" +INSTANCE_REQUIREMENTS_STEM = "sam-property-capacityprovider-instancerequirements" +SCALING_CONFIG_STEM = "sam-property-capacityprovider-scalingconfig" + +properties = get_prop(PROPERTIES_STEM) +vpcconfig = get_prop(VPC_CONFIG_STEM) +instancerequirements = get_prop(INSTANCE_REQUIREMENTS_STEM) +scalingconfig = get_prop(SCALING_CONFIG_STEM) + + +class VpcConfig(BaseModel): + # Optional list of security group IDs - supports intrinsic functions for dynamic references + SecurityGroupIds: Optional[List[SamIntrinsicable[str]]] = vpcconfig("SecurityGroupIds") + # Required list of subnet IDs - supports intrinsic functions for dynamic VPC configuration + SubnetIds: List[SamIntrinsicable[str]] = vpcconfig("SubnetIds") + + +class InstanceRequirements(BaseModel): + # Optional list of CPU architectures - maps to CFN InstanceRequirements.Architecture + # Uses List[SamIntrinsicable[str]] to support intrinsic functions like !Ref for dynamic architecture values + Architectures: Optional[List[SamIntrinsicable[str]]] = instancerequirements("Architectures") + # Optional list of allowed EC2 instance types - maps to CFN InstanceRequirements.AllowedInstanceTypes + # Uses List[SamIntrinsicable[str]] to support intrinsic functions like !Ref for dynamic instance types + AllowedTypes: Optional[List[SamIntrinsicable[str]]] = instancerequirements("AllowedTypes") + # Optional list of excluded EC2 instance types - maps to CFN InstanceRequirements.ExcludedInstanceTypes + # Uses List[SamIntrinsicable[str]] to support intrinsic functions like !Ref for dynamic instance types + ExcludedTypes: Optional[List[SamIntrinsicable[str]]] = instancerequirements("ExcludedTypes") + + +class ScalingConfig(BaseModel): + # Optional maximum instance count - maps to CFN CapacityProviderScalingConfig.MaxVCpuCount + # Uses SamIntrinsicable[int] to support dynamic scaling limits via parameters/conditions + MaxVCpuCount: Optional[SamIntrinsicable[int]] = scalingconfig("MaxVCpuCount") + # Average CPU utilization target (0-100) - maps to CFN ScalingPolicies with CPU metric type + # When specified, automatically sets ScalingMode to "Manual" + # Uses SamIntrinsicable[float] to support dynamic scaling targets via parameters/conditions + AverageCPUUtilization: Optional[SamIntrinsicable[float]] = scalingconfig("AverageCPUUtilization") + + +class Properties(BaseModel): + # TODO: Change back to passthrough_prop after CloudFormation schema is updated with AWS::Lambda::CapacityProvider + # Optional capacity provider name - passes through directly to CFN AWS::Lambda::CapacityProvider + # Uses PassThroughProp because it's a direct 1:1 mapping with no SAM transformation + # CapacityProviderName: Optional[PassThroughProp] = passthrough_prop( + # PROPERTIES_STEM, + # "CapacityProviderName", + # ["AWS::Lambda::CapacityProvider", "Properties", "CapacityProviderName"], + # ) + CapacityProviderName: Optional[PassThroughProp] # TODO: add documentation + + # Required VPC configuration - preserves CFN structure, required for EC2 instance networking + # Uses custom VpcConfig class to validate required SubnetIds while maintaining passthrough behavior + VpcConfig: VpcConfig = properties("VpcConfig") + + # Optional operator role ARN - if not provided, SAM auto-generates one with EC2 management permissions + OperatorRole: Optional[PassThroughProp] = properties("OperatorRole") + + # Optional tags - SAM transforms key-value pairs to CFN Tag objects before passing to CFN + # Uses DictStrAny to support flexible tag structure with string keys and any values + Tags: Optional[DictStrAny] = properties("Tags") + + # Optional flag to propagate tags to resources created by this capacity provider + # When true, all tags defined on the capacity provider will be propagated to generated resources + PropagateTags: Optional[bool] = properties("PropagateTags") + + # Optional instance requirements - maps to CFN InstanceRequirements with property name shortening + # Uses custom InstanceRequirements class because SAM shortens names + InstanceRequirements: Optional[InstanceRequirements] = properties("InstanceRequirements") + + # Optional scaling configuration - maps to CFN CapacityProviderScalingConfig + # Uses custom ScalingConfig class because SAM renames construct (CapacityProviderScalingConfig→ScalingConfig) + ScalingConfig: Optional[ScalingConfig] = properties("ScalingConfig") + + # TODO: Change back to passthrough_prop after CloudFormation schema is updated with AWS::Lambda::CapacityProvider + # Optional KMS key ARN - passes through directly to CFN for encryption configuration + # Uses PassThroughProp because it's a direct 1:1 mapping with no SAM transformation + # KMSKeyArn: Optional[PassThroughProp] = passthrough_prop( + # PROPERTIES_STEM, + # "KMSKeyArn", + # ["AWS::Lambda::CapacityProvider", "Properties", "KMSKeyArn"], + # ) + KMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + + +class Globals(BaseModel): + # Global VPC configuration - can be inherited by capacity providers if not overridden + # Uses custom VpcConfig class to validate required SubnetIds while maintaining passthrough behavior + VpcConfig: Optional[VpcConfig] = properties("VpcConfig") + + # Global operator role ARN - can be inherited by capacity providers if not overridden + OperatorRole: Optional[PassThroughProp] = properties("OperatorRole") + + # Global tags - can be inherited and merged with resource-specific tags + # Uses DictStrAny to support flexible tag structure with string keys and any values + Tags: Optional[DictStrAny] = properties("Tags") + + # Global flag to propagate tags to resources created by capacity providers + # When true, all tags defined on capacity providers will be propagated to generated resources + PropagateTags: Optional[bool] = properties("PropagateTags") + + # Global instance requirements - can be inherited by capacity providers if not overridden + # Uses custom InstanceRequirements class because SAM shortens names + InstanceRequirements: Optional[InstanceRequirements] = properties("InstanceRequirements") + + # Global scaling configuration - can be inherited by capacity providers if not overridden + # Uses custom ScalingConfig class because SAM renames construct (CapacityProviderScalingConfig→ScalingConfig) + ScalingConfig: Optional[ScalingConfig] = properties("ScalingConfig") + + KMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + + +class Resource(ResourceAttributes): + # Literal type ensures only correct resource type is accepted + Type: Literal["AWS::Serverless::CapacityProvider"] + # Required properties using the Properties class for full validation + Properties: Properties diff --git a/samtranslator/internal/schema_source/aws_serverless_function.py b/samtranslator/internal/schema_source/aws_serverless_function.py index e40d193b4a..13d716cfe2 100644 --- a/samtranslator/internal/schema_source/aws_serverless_function.py +++ b/samtranslator/internal/schema_source/aws_serverless_function.py @@ -20,6 +20,7 @@ alexaskilleventproperties = get_prop("sam-property-function-alexaskill") apiauth = get_prop("sam-property-function-apifunctionauth") apieventproperties = get_prop("sam-property-function-api") +capacityproviderconfig = get_prop("sam-property-function-capacityproviderconfig") cloudwatcheventproperties = get_prop("sam-property-function-cloudwatchevent") cloudwatchlogseventproperties = get_prop("sam-property-function-cloudwatchlogs") codeuri = get_prop("sam-property-function-functioncode") @@ -535,6 +536,16 @@ class ScheduleV2Event(BaseModel): TenancyConfig = Optional[PassThroughProp] +class CapacityProviderConfig(BaseModel): + Arn: SamIntrinsicable[str] = capacityproviderconfig("Arn") + PerExecutionEnvironmentMaxConcurrency: Optional[SamIntrinsicable[int]] = capacityproviderconfig( + "PerExecutionEnvironmentMaxConcurrency" + ) + ExecutionEnvironmentMemoryGiBPerVCpu: Optional[SamIntrinsicable[Union[int, float]]] = capacityproviderconfig( + "ExecutionEnvironmentMemoryGiBPerVCpu" + ) + + class Properties(BaseModel): Architectures: Optional[Architectures] = passthrough_prop( PROPERTIES_STEM, @@ -661,6 +672,12 @@ class Properties(BaseModel): LoggingConfig: Optional[PassThroughProp] # TODO: add documentation RecursiveLoop: Optional[PassThroughProp] # TODO: add documentation SourceKMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + CapacityProviderConfig: Optional[CapacityProviderConfig] = prop("CapacityProviderConfig") # TODO: add documentation + FunctionScalingConfig: Optional[PassThroughProp] # TODO: add documentation + VersionDeletionPolicy: Optional[SamIntrinsicable[Union[str, bool]]] = prop( + "VersionDeletionPolicy" + ) # TODO: add documentation + PublishToLatestPublished: Optional[SamIntrinsicable[Union[str, bool]]] # TODO: add documentation TenancyConfig: Optional[PassThroughProp] # TODO: add documentation @@ -722,6 +739,12 @@ class Globals(BaseModel): LoggingConfig: Optional[PassThroughProp] # TODO: add documentation RecursiveLoop: Optional[PassThroughProp] # TODO: add documentation SourceKMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + CapacityProviderConfig: Optional[CapacityProviderConfig] = prop("CapacityProviderConfig") # TODO: add documentation + FunctionScalingConfig: Optional[PassThroughProp] # TODO: add documentation + VersionDeletionPolicy: Optional[SamIntrinsicable[Union[str, bool]]] = prop( + "VersionDeletionPolicy" + ) # TODO: add documentation + PublishToLatestPublished: Optional[SamIntrinsicable[Union[str, bool]]] # TODO: add documentation TenancyConfig: Optional[PassThroughProp] # TODO: add documentation diff --git a/samtranslator/internal/schema_source/sam-docs.json b/samtranslator/internal/schema_source/sam-docs.json index 464620c1af..390ce884b3 100644 --- a/samtranslator/internal/schema_source/sam-docs.json +++ b/samtranslator/internal/schema_source/sam-docs.json @@ -1,5 +1,28 @@ { "properties": { + "sam-resource-capacityprovider": { + "CapacityProviderName": "The name of the capacity provider. If not specified, AWS SAM generates a unique name.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityprovidername) property of an `AWS::Lambda::CapacityProvider` resource.", + "VpcConfig": "VPC configuration for the capacity provider.\n*Type*: [VpcConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-vpcconfig.html)\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-vpcconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "OperatorRole": "The ARN of the capacity provider operator role. If not provided, SAM auto-generates one with EC2 management permissions.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderOperatorRoleArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-permissionsconfig.html#cfn-lambda-capacityprovider-permissionsconfig-capacityprovideroperatorrolearn) property of the `AWS::Lambda::CapacityProvider` `PermissionsConfig` data type.", + "Tags": "A map of key-value pairs to apply to the capacity provider.\n*Type*: Map\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-tags) property of an `AWS::Lambda::CapacityProvider` resource.", + "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-capacityprovider.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "InstanceRequirements": "Instance requirements for the capacity provider.\n*Type*: [InstanceRequirements](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-instancerequirements.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`InstanceRequirements`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-instancerequirements) property of an `AWS::Lambda::CapacityProvider` resource.", + "ScalingConfig": "Scaling configuration for the capacity provider.\n*Type*: [ScalingConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-scalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "KMSKeyArn": "The ARN of the AWS KMS key used to encrypt the capacity provider.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`KMSKeyArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-kmskeyarn) property of an `AWS::Lambda::CapacityProvider` resource." + }, + "sam-property-capacityprovider-vpcconfig": { + "SecurityGroupIds": "A list of VPC security group IDs.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityGroupIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-securitygroupids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type.", + "SubnetIds": "A list of VPC subnet IDs.\n*Type*: List of String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SubnetIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-subnetids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type." + }, + "sam-property-capacityprovider-instancerequirements": { + "Architectures": "The CPU architecture for the instances.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Architecture`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-architecture) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "AllowedTypes": "The allowed instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`AllowedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-allowedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "ExcludedTypes": "The excluded instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExcludedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-excludedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type." + }, + "sam-property-capacityprovider-scalingconfig": { + "MaxVCpuCount": "The maximum number of compute instances that the capacity provider can scale up to.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaxVCpuCount`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-capacityproviderscalingconfig.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig-maxvcpucount) property of the `AWS::Lambda::CapacityProvider` `CapacityProviderScalingConfig` data type.", + "AverageCPUUtilization": "A target tracking scaling policy based on average CPU utilization. Lambda will automatically adjusts the capacity provider's compute resources to this a specified target value.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is transformed to a scaling policy with `PredefinedMetricType` of `LambdaCapacityProviderAverageCPUUtilization`." + }, "sam-property-api-apiauth": { "AddApiKeyRequiredToCorsPreflight": "If the `ApiKeyRequired` and `Cors` properties are set, then setting `AddApiKeyRequiredToCorsPreflight` will cause the API key to be added to the `Options` property\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `True` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "AddDefaultAuthorizerToCorsPreflight": "If the `DefaultAuthorizer` and `Cors` properties are set, then setting `AddDefaultAuthorizerToCorsPreflight` will cause the default authorizer to be added to the `Options` property in the OpenAPI section\\. \n*Type*: Boolean \n*Required*: No \n*Default*: True \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", @@ -142,6 +165,11 @@ "OverrideApiAuth": "Specify as `true` to override the global authorizer configuration of your `AWS::Serverless::Api` resource\\. This property is only required if you specify a global authorizer and use the `DefinitionBody` property of an `AWS::Serverless::Api` resource to describe your API\\. \nWhen you specify `OverrideApiAuth` as `true`, AWS SAM will override your global authorizer with any values provided for `ApiKeyRequired`, `Authorizer`, or `ResourcePolicy`\\. Therefore, at least one of these properties must also be specified when using `OverrideApiAuth`\\. For an example, see [ Override a global authorizer when DefinitionBody for AWS::Serverless::Api is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-property-function-apifunctionauth--examples--override2.html#sam-property-function-apifunctionauth--examples--override2)\\.\n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "ResourcePolicy": "Configure Resource Policy for this path on an API\\. \n*Type*: [ResourcePolicyStatement](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-resourcepolicystatement.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\." }, + "sam-property-function-capacityproviderconfig": { + "Arn": "The ARN of the capacity provider.\n*Type*: String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-capacityproviderarn) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "PerExecutionEnvironmentMaxConcurrency": "The maximum concurrency for the execution environment.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`PerExecutionEnvironmentMaxConcurrency`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-perexecutionenvironmentmaxconcurrency) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "ExecutionEnvironmentMemoryGiBPerVCpu": "The memory in GiB per vCPU for the execution environment.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExecutionEnvironmentMemoryGiBPerVCpu`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-executionenvironmentmemorygibpervcpu) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type." + }, "sam-property-function-cloudwatchevent": { "Enabled": "Indicates whether the rule is enabled\\. \nTo disable the rule, set this property to `false`\\. \nSpecify either the `Enabled` or `State` property, but not both\\.\n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`State`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#cfn-events-rule-state) property of an `AWS::Events::Rule` resource\\. If this property is set to `true` then AWS SAM passes `ENABLED`, otherwise it passes `DISABLED`\\.", "EventBusName": "The event bus to associate with this rule\\. If you omit this property, AWS SAM uses the default event bus\\. \n*Type*: String \n*Required*: No \n*Default*: Default event bus \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EventBusName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#cfn-events-rule-eventbusname) property of an `AWS::Events::Rule` resource\\.", @@ -701,6 +729,7 @@ "AutoPublishAlias": "The name of the Lambda alias\\. For more information about Lambda aliases, see [Lambda function aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) in the *AWS Lambda Developer Guide*\\. For examples that use this property, see [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\. \nAWS SAM generates [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html) and [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html) resources when this property is set\\. For information about this scenario, see [AutoPublishAlias property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-function.html#sam-specification-generated-resources-function-autopublishalias)\\. For general information about generated AWS CloudFormation resources, see [Generated AWS CloudFormation resources for AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources.html)\\. \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\\.", "AutoPublishAliasAllProperties": "Specifies when a new [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html) is created\\. When `true`, a new Lambda version is created when any property in the Lambda function is modified\\. When `false`, a new Lambda version is created only when any of the following properties are modified: \n+ `Environment`, `MemorySize`, or `SnapStart`\\.\n+ Any change that results in an update to the `Code` property, such as `CodeDict`, `ImageUri`, or `InlineCode`\\.\nThis property requires `AutoPublishAlias` to be defined\\. \nIf `AutoPublishSha256` is also specified, its behavior takes precedence over `AutoPublishAliasAllProperties: true`\\. \n*Type*: Boolean \n*Required*: No \n*Default value*: `false` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "AutoPublishCodeSha256": "When used, this string works with the `CodeUri` value to determine if a new Lambda version needs to be published\\. This property is often used to resolve the following deployment issue: A deployment package is stored in an Amazon S3 location and is replaced by a new deployment package with updated Lambda function code but the `CodeUri` property remains unchanged \\(as opposed to the new deployment package being uploaded to a new Amazon S3 location and the `CodeUri` being changed to the new location\\)\\. \nThis problem is marked by an AWS SAM template having the following characteristics: \n+ The `DeploymentPreference` object is configured for gradual deployments \\(as described in [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\)\n+ The `AutoPublishAlias` property is set and doesn't change between deployments\n+ The `CodeUri` property is set and doesn't change between deployments\\.\nIn this scenario, updating `AutoPublishCodeSha256` results in a new Lambda version being created successfully\\. However, new function code deployed to Amazon S3 will not be recognized\\. To recognize new function code, consider using versioning in your Amazon S3 bucket\\. Specify the `Version` property for your Lambda function and configure your bucket to always use the latest deployment package\\. \nIn this scenario, to trigger the gradual deployment successfully, you must provide a unique value for `AutoPublishCodeSha256`\\. \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\\.", + "CapacityProviderConfig": "Configuration for using a Lambda capacity provider with this function.\n*Type*: [CapacityProviderConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-capacityproviderconfig.html)\n*Required*", "CodeSigningConfigArn": "The ARN of the [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html) resource, used to enable code signing for this function\\. For more information about code signing, see [Set up code signing for your AWS SAM application](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/authoring-codesigning.html)\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CodeSigningConfigArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-codesigningconfigarn) property of an `AWS::Lambda::Function` resource\\.", "CodeUri": "The code for the function\\. Accepted values include: \n+ The function's Amazon S3 URI\\. For example, `s3://bucket-123456789/sam-app/1234567890abcdefg`\\.\n+ The local path to the function\\. For example, `hello_world/`\\.\n+ A [FunctionCode](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-functioncode.html) object\\.\nIf you provide a function's Amazon S3 URI or [FunctionCode](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-functioncode.html) object, you must reference a valid [Lambda deployment package](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html)\\. \nIf you provide a local file path, use the AWS SAM\u00a0CLI to upload the local file at deployment\\. To learn more, see [How to upload local files at deployment with AWS SAM\u00a0CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/deploy-upload-local-files.html)\\. \nIf you use intrinsic functions in `CodeUri` property, AWS SAM will not be able to correctly parse the values\\. Consider using [AWS::LanguageExtensions transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-aws-languageextensions.html) instead\\.\n*Type*: \\[ String \\| [FunctionCode](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-functioncode.html) \\] \n*Required*: Conditional\\. When `PackageType` is set to `Zip`, one of `CodeUri` or `InlineCode` is required\\. \n*AWS CloudFormation compatibility*: This property is similar to the `[ Code](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-code)` property of an `AWS::Lambda::Function` resource\\. The nested Amazon S3 properties are named differently\\.", "DeadLetterQueue": "Configures an Amazon Simple Notification Service \\(Amazon SNS\\) topic or Amazon Simple Queue Service \\(Amazon SQS\\) queue where Lambda sends events that it can't process\\. For more information about dead\\-letter queue functionality, see [Dead\\-letter queues](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-dlq) in the *AWS Lambda Developer Guide*\\. \nIf your Lambda function's event source is an Amazon SQS queue, configure a dead\\-letter queue for the source queue, not for the Lambda function\\. The dead\\-letter queue that you configure for a function is used for the function's [asynchronous invocation queue](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html), not for event source queues\\.\n*Type*: Map \\| [DeadLetterQueue](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-deadletterqueue.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`DeadLetterConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-deadletterconfig.html) property of an `AWS::Lambda::Function` resource\\. In AWS CloudFormation the type is derived from the `TargetArn`, whereas in AWS SAM you must pass the type along with the `TargetArn`\\.", @@ -713,6 +742,7 @@ "FileSystemConfigs": "List of [FileSystemConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-filesystemconfig.html) objects that specify the connection settings for an Amazon Elastic File System \\(Amazon EFS\\) file system\\. \nIf your template contains an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html) resource, you must also specify a `DependsOn` resource attribute to ensure that the mount target is created or updated before the function\\. \n*Type*: List \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FileSystemConfigs`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-filesystemconfigs) property of an `AWS::Lambda::Function` resource\\.", "FunctionName": "A name for the function\\. If you don't specify a name, a unique name is generated for you\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FunctionName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-functionname) property of an `AWS::Lambda::Function` resource\\.", "FunctionUrlConfig": "The object that describes a function URL\\. A function URL is an HTTPS endpoint that you can use to invoke your function\\. \nFor more information, see [Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html) in the *AWS Lambda Developer Guide*\\. \n*Type*: [FunctionUrlConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-functionurlconfig.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "FunctionScalingConfig": "Configuration for scaling behavior of the function.\n*Type*: [FunctionScalingConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-functionscalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`FunctionScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-functionscalingconfig) property of an `AWS::Lambda::Function` resource.", "Handler": "The function within your code that is called to begin execution\\. This property is only required if the `PackageType` property is set to `Zip`\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Handler`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-handler) property of an `AWS::Lambda::Function` resource\\.", "ImageConfig": "The object used to configure Lambda container image settings\\. For more information, see [Using container images with Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-images.html) in the *AWS Lambda Developer Guide*\\. \n*Type*: [ImageConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-imageconfig) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ImageConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-imageconfig) property of an `AWS::Lambda::Function` resource\\.", "ImageUri": "The URI of the Amazon Elastic Container Registry \\(Amazon ECR\\) repository for the Lambda function's container image\\. This property only applies if the `PackageType` property is set to `Image`, otherwise it is ignored\\. For more information, see [Using container images with Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-images.html) in the *AWS Lambda Developer Guide*\\. \nIf the `PackageType` property is set to `Image`, then either `ImageUri` is required, or you must build your application with necessary `Metadata` entries in the AWS SAM template file\\. For more information, see [Default build with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-build.html)\\.\nBuilding your application with necessary `Metadata` entries takes precedence over `ImageUri`, so if you specify both then `ImageUri` is ignored\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ImageUri`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-imageuri) property of the `AWS::Lambda::Function` `Code` data type\\.", @@ -726,6 +756,7 @@ "Policies": "Permission policies for this function\\. Policies will be appended to the function's default AWS Identity and Access Management \\(IAM\\) execution role\\. \nThis property accepts a single value or list of values\\. Allowed values include: \n+ [AWS SAM\u00a0policy templates](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html)\\.\n+ The ARN of an [AWS managed policy](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) or [ customer managed policy](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#customer-managed-policies)\\.\n+ The name of an AWS managed policy from the following [ list](https://github.com/aws/serverless-application-model/blob/develop/samtranslator/internal/data/aws_managed_policies.json)\\.\n+ An [ inline IAM policy](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#inline-policies) formatted in YAML as a map\\.\nIf you set the `Role` property, this property is ignored\\.\n*Type*: String \\| List \\| Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Policies`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-policies) property of an `AWS::IAM::Role` resource\\.", "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-function.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "ProvisionedConcurrencyConfig": "The provisioned concurrency configuration of a function's alias\\. \n`ProvisionedConcurrencyConfig` can be specified only if the `AutoPublishAlias` is set\\. Otherwise, an error results\\.\n*Type*: [ProvisionedConcurrencyConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ProvisionedConcurrencyConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) property of an `AWS::Lambda::Alias` resource\\.", + "PublishToLatestPublished": "Whether to publish the latest snapshot to the $LATEST.PUBLISHED version.\n*Type*: Boolean\n*Required*: No\n*AWS CloudFormation compatibility*: *AWS CloudFormation compatibility*: This property is passed directly to the [`PublishToLatestPublished`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-publishtolatestpublished)", "ReservedConcurrentExecutions": "The maximum number of concurrent executions that you want to reserve for the function\\. \nFor more information about this property, see [Lambda Function Scaling](https://docs.aws.amazon.com/lambda/latest/dg/scaling.html) in the *AWS Lambda Developer Guide*\\. \n*Type*: Integer \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ReservedConcurrentExecutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-reservedconcurrentexecutions) property of an `AWS::Lambda::Function` resource\\.", "Role": "The ARN of an IAM role to use as this function's execution role\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Role`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-role) property of an `AWS::Lambda::Function` resource\\. This is required in AWS CloudFormation but not in AWS SAM\\. If a role isn't specified, one is created for you with a logical ID of `Role`\\.", "RolePath": "The path to the function's IAM execution role\\. \nUse this property when the role is generated for you\\. Do not use when the role is specified with the `Role` property\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Path`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-path) property of an `AWS::IAM::Role` resource\\.", @@ -736,6 +767,7 @@ "Timeout": "The maximum time in seconds that the function can run before it is stopped\\. \n*Type*: Integer \n*Required*: No \n*Default*: 3 \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Timeout`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-timeout) property of an `AWS::Lambda::Function` resource\\.", "Tracing": "The string that specifies the function's X\\-Ray tracing mode\\. \n+ `Active` \u2013 Activates X\\-Ray tracing for the function\\.\n+ `Disabled` \u2013 Deactivates X\\-Ray for the function\\.\n+ `PassThrough` \u2013 Activates X\\-Ray tracing for the function\\. Sampling decision is delegated to the downstream services\\.\nIf specified as `Active` or `PassThrough` and the `Role` property is not set, AWS SAM adds the `arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess` policy to the Lambda execution role that it creates for you\\. \nFor more information about X\\-Ray, see [Using AWS Lambda with AWS X\\-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) in the *AWS Lambda Developer Guide*\\. \n*Valid values*: \\[`Active`\\|`Disabled`\\|`PassThrough`\\] \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`TracingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-tracingconfig) property of an `AWS::Lambda::Function` resource\\.", "VersionDescription": "Specifies the `Description` field that is added on the new Lambda version resource\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Description`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html#cfn-lambda-version-description) property of an `AWS::Lambda::Version` resource\\.", + "VersionDeletionPolicy": "Policy for deleting old versions of the function. This will set [DeletionPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html) attribute for the version resource when use with AutoPublishAlias\n*Type*: String\n*Required*: No\n*Valid values*: `Retain` or `Delete`\n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.", "VpcConfig": "The configuration that enables this function to access private resources within your virtual private cloud \\(VPC\\)\\. \n*Type*: [VpcConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) property of an `AWS::Lambda::Function` resource\\." }, "sam-resource-graphqlapi": { diff --git a/samtranslator/internal/schema_source/schema.py b/samtranslator/internal/schema_source/schema.py index 02ff7f903f..f83df3db97 100644 --- a/samtranslator/internal/schema_source/schema.py +++ b/samtranslator/internal/schema_source/schema.py @@ -11,6 +11,7 @@ any_cfn_resource, aws_serverless_api, aws_serverless_application, + aws_serverless_capacity_provider, aws_serverless_connector, aws_serverless_function, aws_serverless_graphqlapi, @@ -29,6 +30,7 @@ class Globals(BaseModel): SimpleTable: Optional[aws_serverless_simpletable.Globals] StateMachine: Optional[aws_serverless_statemachine.Globals] LayerVersion: Optional[aws_serverless_layerversion.Globals] + CapacityProvider: Optional[aws_serverless_capacity_provider.Globals] Resources = Union[ @@ -41,6 +43,7 @@ class Globals(BaseModel): aws_serverless_httpapi.Resource, aws_serverless_application.Resource, aws_serverless_graphqlapi.Resource, + aws_serverless_capacity_provider.Resource, ] diff --git a/samtranslator/model/__init__.py b/samtranslator/model/__init__.py index e47131793e..3005d24933 100644 --- a/samtranslator/model/__init__.py +++ b/samtranslator/model/__init__.py @@ -1,9 +1,10 @@ -""" CloudFormation Resource serialization, deserialization, and validation """ +"""CloudFormation Resource serialization, deserialization, and validation""" import inspect import re from abc import ABC, ABCMeta, abstractmethod from contextlib import suppress +from enum import Enum from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar from samtranslator.compat import pydantic @@ -19,6 +20,23 @@ RT = TypeVar("RT", bound=pydantic.BaseModel) # return type +class StringEnumExpectedType: + """Expected type wrapper for string enum validators.""" + + def __init__(self, enum_values: List[str]): + # Format description based on number of values + num_values = len(enum_values) + if num_values == 1: + description = f"the string '{enum_values[0]}'" + elif num_values == 2: # noqa: PLR2004 + description = f"one of the strings: '{enum_values[0]}' or '{enum_values[1]}'" + else: + quoted_values = [f"'{v}'" for v in enum_values] + description = f"one of the strings: {', '.join(quoted_values[:-1])}, or {quoted_values[-1]}" + + self.value = (description, str) + + class PropertyType: """Stores validation information for a CloudFormation resource property. @@ -47,7 +65,16 @@ def __init__( self.required = required self.validate = validate self.supports_intrinsics = supports_intrinsics - self.expected_type = self.EXPECTED_TYPE_BY_VALIDATOR.get(validate) + self.expected_type = self._resolve_expected_type(validate) + + def _resolve_expected_type(self, validate: Validator) -> Optional[Any]: + """Resolve expected_type from validator attribute or default mapping.""" + # Check if validator has enum_values attribute (from IS_STR_ENUM) + if hasattr(validate, "enum_values"): + return StringEnumExpectedType(validate.enum_values) + + # Default mapping for standard validators + return self.EXPECTED_TYPE_BY_VALIDATOR.get(validate) class Property(PropertyType): @@ -163,7 +190,7 @@ def __init__( self.set_resource_attribute(attr, value) @classmethod - def get_supported_resource_attributes(cls): # type: ignore[no-untyped-def] + def get_supported_resource_attributes(cls) -> Tuple[str, ...]: """ A getter method for the supported resource attributes returns: a tuple that contains the name of all supported resource attributes @@ -205,7 +232,7 @@ def from_dict(cls, logical_id: str, resource_dict: Dict[str, Any], relative_id: resource = cls(logical_id, relative_id=relative_id) - resource._validate_resource_dict(logical_id, resource_dict) # type: ignore[no-untyped-call] + resource._validate_resource_dict(logical_id, resource_dict) # Default to empty properties dictionary. If customers skip the Properties section, an empty dictionary # accurately captures the intent. @@ -247,7 +274,7 @@ def _validate_logical_id(logical_id: Optional[Any]) -> str: raise InvalidResourceException(str(logical_id), "Logical ids must be alphanumeric.") @classmethod - def _validate_resource_dict(cls, logical_id, resource_dict): # type: ignore[no-untyped-def] + def _validate_resource_dict(cls, logical_id: str, resource_dict: Dict[str, Any]) -> None: """Validates that the provided resource dict contains the correct Type string, and the required Properties dict. :param dict resource_dict: the resource dict to validate @@ -335,22 +362,82 @@ def __setattr__(self, name, value): # type: ignore[no-untyped-def] ) # Note: For compabitliy issue, we should ONLY use this with new abstraction/resources. - def validate_properties_and_return_model(self, cls: Type[RT]) -> RT: + def validate_properties_and_return_model(self, cls: Type[RT], collect_all_errors: bool = False) -> RT: """ Given a resource properties, return a typed object from the definitions of SAM schema model - param: - resource_properties: properties from input template + Args: cls: schema models + collect_all_errors: If True, collect all validation errors. If False (default), only first error. """ try: return cls.parse_obj(self._generate_resource_dict()["Properties"]) except pydantic.error_wrappers.ValidationError as e: + if collect_all_errors: + # Comprehensive error collection with union type consolidation + error_messages = self._format_all_errors(e.errors()) # type: ignore[arg-type] + raise InvalidResourceException(self.logical_id, " ".join(error_messages)) from e error_properties: str = "" with suppress(KeyError): error_properties = ".".join(str(x) for x in e.errors()[0]["loc"]) raise InvalidResourceException(self.logical_id, f"Property '{error_properties}' is invalid.") from e + def _format_all_errors(self, errors: List[Dict[str, Any]]) -> List[str]: + """Format all validation errors, consolidating union type errors in single pass.""" + type_mapping = { + "not a valid dict": "dictionary", + "not a valid int": "integer", + "not a valid float": "number", + "not a valid list": "list", + "not a valid str": "string", + } + + # Group errors by path in a single pass + path_to_errors: Dict[str, Dict[str, Any]] = {} + + for error in errors: + property_path = ".".join(str(x) for x in error["loc"]) + raw_message = error.get("msg", "") + + # Extract type for union consolidation + extracted_type = None + for pattern, type_name in type_mapping.items(): + if pattern in raw_message: + extracted_type = type_name + break + + if property_path not in path_to_errors: + path_to_errors[property_path] = {"types": [], "error": error} + + if extracted_type: + path_to_errors[property_path]["types"].append(extracted_type) + + # Format messages based on collected data + result = [] + for path, data in path_to_errors.items(): + unique_types = list(dict.fromkeys(data["types"])) # Remove duplicates, preserve order + + if len(unique_types) > 1: + # Multiple types - consolidate with union + type_text = " or ".join(unique_types) + result.append(f"Property '{path}' value must be {type_text}.") + else: + # Single or no types - format normally + result.append(self._format_single_error(data["error"])) + + return result + + def _format_single_error(self, error: Dict[str, Any]) -> str: + """Format a single Pydantic error into user-friendly message.""" + property_path = ".".join(str(x) for x in error["loc"]) + raw_message = error["msg"] + + if error["type"] == "value_error.missing": + return f"Property '{property_path}' is required." + if "extra fields not permitted" in raw_message: + return f"Property '{property_path}' is an invalid property." + return f"Property '{property_path}' {raw_message.lower()}." + def validate_properties(self) -> None: """Validates that the required properties for this Resource have been populated, and that all properties have valid values. @@ -481,6 +568,16 @@ def to_cloudformation(self, **kwargs: Any) -> List[Any]: """ +class ValidationRule(Enum): + MUTUALLY_EXCLUSIVE = "mutually_exclusive" + MUTUALLY_INCLUSIVE = "mutually_inclusive" + CONDITIONAL_REQUIREMENT = "conditional_requirement" + + +# Simple tuple-based rules: (rule_type, [property_names]) +PropertyRule = Tuple[ValidationRule, List[str]] + + class SamResourceMacro(ResourceMacro, metaclass=ABCMeta): """ResourceMacro that specifically refers to SAM (AWS::Serverless::*) resources.""" @@ -536,14 +633,14 @@ def get_resource_references(self, generated_cfn_resources, supported_resource_re def _construct_tag_list( self, tags: Optional[Dict[str, Any]], additional_tags: Optional[Dict[str, Any]] = None ) -> List[Dict[str, Any]]: - if not bool(tags): - tags = {} + tags_dict: Dict[str, Any] = tags or {} if additional_tags is None: additional_tags = {} + # At this point tags is guaranteed to be a Dict[str, Any] since we set it to {} if it was falsy for tag in self._RESERVED_TAGS: - self._check_tag(tag, tags) # type: ignore[no-untyped-call] + self._check_tag(tag, tags_dict) sam_tag = {self._SAM_KEY: self._SAM_VALUE} @@ -553,6 +650,40 @@ def _construct_tag_list( # customer's knowledge. return get_tag_list(sam_tag) + get_tag_list(additional_tags) + get_tag_list(tags) + @staticmethod + def propagate_tags_combine( + resources: List[Resource], tags: Optional[Dict[str, Any]], propagate_tags: Optional[bool] = False + ) -> None: + """ + Propagates tags to the resources + Similar to propagate_tags() method but this method will combine provided tags with existing resource tags. + + Note: + - This method created after propagate_tags() to combine propagate tags with resource tags create during to_cloudformation() + - Create this method because updating propagate_tags() will cause regression issue; + - Use this method for new resource if you want to assign combined tags, not replace. + + :param propagate_tags: Whether we should pass the tags to generated resources. + :param resources: List of generated resources + :param tags: dictionary of tags to propagate to the resources. + + :return: None + """ + if not propagate_tags or not tags: + return + + for resource in resources: + if hasattr(resource, "Tags"): + if resource.Tags: + propagated_tags = get_tag_list(tags) + combined_tags = [ + {"Key": k, "Value": v} + for k, v in {tag["Key"]: tag["Value"] for tag in resource.Tags + propagated_tags}.items() + ] + resource.Tags = combined_tags + else: + resource.assign_tags(tags) + @staticmethod def propagate_tags( resources: List[Resource], tags: Optional[Dict[str, Any]], propagate_tags: Optional[bool] = False @@ -572,7 +703,7 @@ def propagate_tags( for resource in resources: resource.assign_tags(tags) - def _check_tag(self, reserved_tag_name, tags): # type: ignore[no-untyped-def] + def _check_tag(self, reserved_tag_name: str, tags: Dict[str, Any]) -> None: if reserved_tag_name in tags: raise InvalidResourceException( self.logical_id, @@ -582,6 +713,71 @@ def _check_tag(self, reserved_tag_name, tags): # type: ignore[no-untyped-def] "input.", ) + def validate_before_transform(self, schema_class: Optional[Type[RT]], collect_all_errors: bool = False) -> None: + if not hasattr(self, "__validation_rules__"): + return + + rules = self.__validation_rules__ + validated_model = ( + self.validate_properties_and_return_model(schema_class, collect_all_errors) if schema_class else None + ) + + error_messages = [] + + for rule_type, properties in rules: + present = [prop for prop in properties if self._get_property_value(prop, validated_model) is not None] + if rule_type == ValidationRule.MUTUALLY_EXCLUSIVE: + # Check if more than one property exists + if len(present) > 1: + prop_names = [f"'{p}'" for p in present] + error_messages.append(f"Cannot specify {self._combine_string(prop_names)} together.") + + elif rule_type == ValidationRule.MUTUALLY_INCLUSIVE: + # If any property in the group is present, then all properties in the group must be present + # Check if some but not all properties from the group are present + missing_some_properties = 0 < len(present) < len(properties) + if missing_some_properties: + error_messages.append(f"Properties must be used together: {self._combine_string(properties)}.") + + elif ( + rule_type == ValidationRule.CONDITIONAL_REQUIREMENT + and self._get_property_value(properties[0], validated_model) is not None + and self._get_property_value(properties[1], validated_model) is None + ): + # First property requires second property + error_messages.append(f"'{properties[0]}' requires '{properties[1]}'.") + + # If there are any validation errors, raise a single exception with all error messages + if error_messages: + raise InvalidResourceException(self.logical_id, "\n".join(error_messages)) + + def _combine_string(self, words: List[str]) -> str: + return ", ".join(words[:-1]) + (" and " + words[-1] if len(words) > 1 else words[0] if words else "") + + def _get_property_value(self, prop: str, validated_model: Any = None) -> Any: + """Original property value getter. Supports nested properties with dot notation.""" + if "." not in prop: + # Simple property - use existing logic for direct attributes + return getattr(self, prop, None) + + # Nested property - use validated model + if validated_model is None: + return None + + try: + # Navigate through nested properties using dot notation + value = validated_model + for part in prop.split("."): + if hasattr(value, part): + value = getattr(value, part) + if value is None: + return None + else: + return None + return value + except Exception: + return None + class ResourceTypeResolver: """ResourceTypeResolver maps Resource Types to Resource classes, e.g. AWS::Serverless::Function to @@ -643,7 +839,7 @@ def get_all_resources(self) -> Dict[str, Any]: """Return a dictionary of all resources from the SAM template.""" return self.resources - def get_resource_by_logical_id(self, _input: str) -> Dict[str, Any]: + def get_resource_by_logical_id(self, _input: str) -> Optional[Dict[str, Any]]: """ Recursively find resource with matching Logical ID that are present in the template and returns the value. If it is not in template, this method simply returns the input unchanged. @@ -661,16 +857,16 @@ def get_resource_by_logical_id(self, _input: str) -> Dict[str, Any]: __all__: List[str] = [ "IS_DICT", "IS_STR", - "Validator", - "any_type", - "is_type", - "PropertyType", - "Property", - "PassThroughProperty", "MutatedPassThroughProperty", + "PassThroughProperty", + "Property", + "PropertyType", "Resource", "ResourceMacro", - "SamResourceMacro", - "ResourceTypeResolver", "ResourceResolver", + "ResourceTypeResolver", + "SamResourceMacro", + "Validator", + "any_type", + "is_type", ] diff --git a/samtranslator/model/capacity_provider/__init__.py b/samtranslator/model/capacity_provider/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samtranslator/model/capacity_provider/generators.py b/samtranslator/model/capacity_provider/generators.py new file mode 100644 index 0000000000..40c84b6b3e --- /dev/null +++ b/samtranslator/model/capacity_provider/generators.py @@ -0,0 +1,216 @@ +""" +AWS::Serverless::CapacityProvider resource transformer +""" + +from typing import Any, Dict, List, Optional + +from samtranslator.metrics.method_decorator import cw_timer +from samtranslator.model import Resource +from samtranslator.model.capacity_provider.resources import LambdaCapacityProvider +from samtranslator.model.iam import IAMRole, IAMRolePolicies +from samtranslator.model.intrinsics import fnGetAtt +from samtranslator.model.resource_policies import ResourcePolicies +from samtranslator.model.role_utils.role_constructor import construct_role_for_resource +from samtranslator.model.tags.resource_tagging import get_tag_list +from samtranslator.translator.arn_generator import ArnGenerator + + +class CapacityProviderGenerator: + """ + Generator for Lambda Capacity Provider resources + """ + + def __init__(self, logical_id: str, **kwargs: Any) -> None: + """ + Initialize a CapacityProviderGenerator + + :param logical_id: Logical ID of the SAM Capacity Provider resource + :param kwargs: Configuration parameters including: + - capacity_provider_name: Name of the capacity provider + - vpc_config: VPC configuration for the capacity provider + - operator_role: IAM operator role ARN + - tags: Resource tags + - instance_requirements: Instance type requirements + - scaling_config: Auto-scaling configuration + - kms_key_arn: KMS key ARN for encryption + - depends_on: Resources this capacity provider depends on + - resource_attributes: Resource attributes to add to capacity provider + - passthrough_resource_attributes: Resource attributes to pass to child resources + """ + self.logical_id = logical_id + self.capacity_provider_name = kwargs.get("capacity_provider_name") + self.vpc_config = kwargs.get("vpc_config") or {} + self.operator_role = kwargs.get("operator_role") + self.tags = kwargs.get("tags") + self.instance_requirements = kwargs.get("instance_requirements") or {} + self.scaling_config = kwargs.get("scaling_config") or {} + self.kms_key_arn = kwargs.get("kms_key_arn") + self.depends_on = kwargs.get("depends_on") + self.resource_attributes = kwargs.get("resource_attributes") + self.passthrough_resource_attributes = kwargs.get("passthrough_resource_attributes") + + @cw_timer(prefix="Generator", name="CapacityProvider") + def to_cloudformation(self) -> List[Resource]: + """ + Transform the capacity provider configuration to CloudFormation resources + + :returns: List of CloudFormation resources + """ + resources: List[Resource] = [] + + # Create IAM roles if not provided; + if not self.operator_role: + # 1. Generate one and pass arn to capacity provider resource + operator_iam_role: IAMRole = self._create_operator_role() + resources.append(operator_iam_role) + # 2. Pass ARN to capacity provider resource via self.operator_role + self.operator_role = fnGetAtt(operator_iam_role.logical_id, "Arn") + + # Create the Lambda CapacityProvider resource + capacity_provider = self._create_capacity_provider() + resources.append(capacity_provider) + + return resources + + def _create_capacity_provider(self) -> LambdaCapacityProvider: + """ + Create a Lambda CapacityProvider resource + """ + capacity_provider = LambdaCapacityProvider( + self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes + ) + + # Set the CapacityProviderName if provided + if self.capacity_provider_name: + capacity_provider.CapacityProviderName = self.capacity_provider_name + + # Clean up VpcConfig to remove None values for optional fields + if self.vpc_config: + vpc_config = {"SubnetIds": self.vpc_config["SubnetIds"]} + if "SecurityGroupIds" in self.vpc_config and self.vpc_config["SecurityGroupIds"] is not None: + vpc_config["SecurityGroupIds"] = self.vpc_config["SecurityGroupIds"] + + capacity_provider.VpcConfig = vpc_config + + # Set the OperatorRole if provided (will be updated later if role is auto-generated) + if self.operator_role: + capacity_provider.PermissionsConfig = {"CapacityProviderOperatorRoleArn": self.operator_role} + + # Set the Tags - always add SAM tag, plus any user-provided tags + capacity_provider.Tags = self._transform_tags(self.tags) + + # Set the InstanceRequirements if provided + if self.instance_requirements: + capacity_provider.InstanceRequirements = self._transform_instance_requirements() + + # Set the ScalingConfig if provided + if self.scaling_config: + capacity_provider.CapacityProviderScalingConfig = self._transform_scaling_config() + + # Set the KMSKeyArn if provided + if self.kms_key_arn: + capacity_provider.KMSKeyArn = self.kms_key_arn + + # Pass through resource attributes + if self.passthrough_resource_attributes: + for attr_name, attr_value in self.passthrough_resource_attributes.items(): + capacity_provider.set_resource_attribute(attr_name, attr_value) + + return capacity_provider + + def _ensure_permissions_config(self, capacity_provider: LambdaCapacityProvider) -> None: + """ + Ensure that the PermissionsConfig dictionary exists on the capacity provider + """ + # Using getattr to avoid mypy unreachable statement error + # This is because mypy thinks PermissionsConfig can never be None based on type definitions + if getattr(capacity_provider, "PermissionsConfig", None) is None: + capacity_provider.PermissionsConfig = {} + + def _transform_instance_requirements(self) -> Dict[str, Any]: + """ + Transform the SAM InstanceRequirements to CloudFormation format + """ + instance_requirements = {} + + if "Architectures" in self.instance_requirements: + instance_requirements["Architectures"] = self.instance_requirements["Architectures"] + + if "AllowedTypes" in self.instance_requirements: + instance_requirements["AllowedInstanceTypes"] = self.instance_requirements["AllowedTypes"] + + if "ExcludedTypes" in self.instance_requirements: + instance_requirements["ExcludedInstanceTypes"] = self.instance_requirements["ExcludedTypes"] + + return instance_requirements + + def _transform_scaling_config(self) -> Dict[str, Any]: + """ + Transform the SAM ScalingConfig to CloudFormation format + """ + scaling_config = {} + + if "MaxVCpuCount" in self.scaling_config: + scaling_config["MaxVCpuCount"] = self.scaling_config["MaxVCpuCount"] + + # Handle AverageCPUUtilization structure + if "AverageCPUUtilization" in self.scaling_config: + scaling_config["ScalingMode"] = "Manual" + scaling_policies = [] + + scaling_policies.append( + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": self.scaling_config["AverageCPUUtilization"], + } + ) + + scaling_config["ScalingPolicies"] = scaling_policies + else: + # Default to Auto scaling mode if no AverageCPUUtilization specified + scaling_config["ScalingMode"] = "Auto" + + return scaling_config + + def _transform_tags(self, additional_tags: Optional[Dict[str, Any]] = None) -> List[Dict[str, str]]: + """ + Helper function to generate tags with automatic SAM tag + + :param additional_tags: Optional additional tags to include + :returns: List of tag dictionaries for CloudFormation + """ + tags_dict = additional_tags.copy() if additional_tags else {} + tags_dict["lambda:createdBy"] = "SAM" + return get_tag_list(tags_dict) + + def _create_operator_role(self) -> IAMRole: + """ + Create an IAM role for the Lambda capacity provider operator + """ + + role_logical_id = f"{self.logical_id}OperatorRole" + + # Use the IAM utility to create the assume role policy for Lambda + assume_role_policy_document = IAMRolePolicies.lambda_assume_role_policy() + + # Create the SAM tag using the helper method + tags = self._transform_tags() + + # Get the managed policy ARN with the correct partition + managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn("AWSLambdaManagedEC2ResourceOperator")] + + # Use the role constructor utility + operator_role = construct_role_for_resource( + resource_logical_id=self.logical_id, + attributes=self.passthrough_resource_attributes, + managed_policy_map=None, + assume_role_policy_document=assume_role_policy_document, + resource_policies=ResourcePolicies({}), # Empty resource policies + managed_policy_arns=managed_policy_arns, + tags=tags, + ) + + # Override the logical ID to match the expected format + operator_role.logical_id = role_logical_id + + return operator_role diff --git a/samtranslator/model/capacity_provider/resources.py b/samtranslator/model/capacity_provider/resources.py new file mode 100644 index 0000000000..149963deb6 --- /dev/null +++ b/samtranslator/model/capacity_provider/resources.py @@ -0,0 +1,39 @@ +""" +AWS::Lambda::CapacityProvider resources for SAM +""" + +from typing import Any, Dict, List, Optional + +from samtranslator.model import GeneratedProperty, Resource +from samtranslator.model.intrinsics import fnGetAtt, ref +from samtranslator.utils.types import Intrinsicable + + +class LambdaCapacityProvider(Resource): + """ + AWS::Lambda::CapacityProvider resource + """ + + resource_type = "AWS::Lambda::CapacityProvider" + property_types = { + "CapacityProviderName": GeneratedProperty(), + "VpcConfig": GeneratedProperty(), + "PermissionsConfig": GeneratedProperty(), + "Tags": GeneratedProperty(), + "InstanceRequirements": GeneratedProperty(), + "CapacityProviderScalingConfig": GeneratedProperty(), + "KMSKeyArn": GeneratedProperty(), + } + + CapacityProviderName: Optional[Intrinsicable[str]] + VpcConfig: Dict[str, Any] + PermissionsConfig: Dict[str, Any] + Tags: Optional[List[Dict[str, Any]]] + InstanceRequirements: Optional[Dict[str, Any]] + CapacityProviderScalingConfig: Optional[Dict[str, Any]] + KMSKeyArn: Optional[Intrinsicable[str]] + + runtime_attrs = { + "name": lambda self: ref(self.logical_id), + "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), + } diff --git a/samtranslator/model/cfn_attributes/__init__.py b/samtranslator/model/cfn_attributes/__init__.py new file mode 100644 index 0000000000..b858630f7b --- /dev/null +++ b/samtranslator/model/cfn_attributes/__init__.py @@ -0,0 +1 @@ +"""CloudFormation attributes module.""" diff --git a/samtranslator/model/cfn_attributes/deletion_policy.py b/samtranslator/model/cfn_attributes/deletion_policy.py new file mode 100644 index 0000000000..a05fa5a7ab --- /dev/null +++ b/samtranslator/model/cfn_attributes/deletion_policy.py @@ -0,0 +1,10 @@ +""" +Constants for CloudFormation DeletionPolicy attribute values. +""" + + +class DeletionPolicy: + """Constants for CloudFormation DeletionPolicy values.""" + + DELETE = "Delete" + RETAIN = "Retain" diff --git a/samtranslator/model/exceptions.py b/samtranslator/model/exceptions.py index 1d42429d2d..a14a47f507 100644 --- a/samtranslator/model/exceptions.py +++ b/samtranslator/model/exceptions.py @@ -132,6 +132,12 @@ def __init__( self.key_path = key_path + def __str__(self) -> str: + return self.message + + def __repr__(self) -> str: + return self.message + @staticmethod def _default_message(key_path: str, expected_type: Optional[ExpectedType]) -> str: if expected_type: diff --git a/samtranslator/model/iam.py b/samtranslator/model/iam.py index 7588ef72dc..62681a97a3 100644 --- a/samtranslator/model/iam.py +++ b/samtranslator/model/iam.py @@ -18,6 +18,16 @@ class IAMRole(Resource): runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")} +class IAMInstanceProfile(Resource): + resource_type = "AWS::IAM::InstanceProfile" + property_types = { + "Path": GeneratedProperty(), + "Roles": GeneratedProperty(), + } + + runtime_attrs = {"arn": lambda self: fnGetAtt(self.logical_id, "Arn")} + + class IAMManagedPolicy(Resource): resource_type = "AWS::IAM::ManagedPolicy" property_types = { diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index e591277238..652d66e0f5 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -36,6 +36,9 @@ class LambdaFunction(Resource): "RuntimeManagementConfig": GeneratedProperty(), "LoggingConfig": GeneratedProperty(), "RecursiveLoop": GeneratedProperty(), + "CapacityProviderConfig": GeneratedProperty(), + "FunctionScalingConfig": GeneratedProperty(), + "PublishToLatestPublished": GeneratedProperty(), "TenancyConfig": GeneratedProperty(), } @@ -65,6 +68,9 @@ class LambdaFunction(Resource): RuntimeManagementConfig: Optional[Dict[str, Any]] LoggingConfig: Optional[Dict[str, Any]] RecursiveLoop: Optional[str] + CapacityProviderConfig: Optional[Dict[str, Any]] + FunctionScalingConfig: Optional[Dict[str, Any]] + PublishToLatestPublished: Optional[Dict[str, Any]] TenancyConfig: Optional[Dict[str, Any]] runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")} @@ -76,6 +82,7 @@ class LambdaVersion(Resource): "CodeSha256": GeneratedProperty(), "Description": GeneratedProperty(), "FunctionName": GeneratedProperty(), + "FunctionScalingConfig": GeneratedProperty(), } runtime_attrs = { diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 3cafe9634d..fde581d90a 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 import re @@ -34,8 +34,12 @@ SyncConfigType, UserPoolConfigType, ) -from samtranslator.internal.schema_source import aws_serverless_graphqlapi -from samtranslator.internal.schema_source.common import PermissionsType +from samtranslator.internal.schema_source import ( + aws_serverless_capacity_provider, + aws_serverless_function, + aws_serverless_graphqlapi, +) +from samtranslator.internal.schema_source.common import PermissionsType, SamIntrinsicable from samtranslator.internal.types import GetManagedPolicyMap from samtranslator.internal.utils.utils import passthrough_value, remove_none_values from samtranslator.intrinsics.resolver import IntrinsicsResolver @@ -49,6 +53,7 @@ ResourceResolver, ResourceTypeResolver, SamResourceMacro, + ValidationRule, ) from samtranslator.model.apigateway import ( ApiGatewayApiKey, @@ -61,6 +66,8 @@ ) from samtranslator.model.apigatewayv2 import ApiGatewayV2DomainName, ApiGatewayV2Stage from samtranslator.model.architecture import ARM64, X86_64 +from samtranslator.model.capacity_provider.generators import CapacityProviderGenerator +from samtranslator.model.cfn_attributes.deletion_policy import DeletionPolicy from samtranslator.model.cloudformation import NestedStack from samtranslator.model.connector.connector import ( UNSUPPORTED_CONNECTOR_PROFILE_TYPE, @@ -114,6 +121,7 @@ IS_INT, IS_LIST, IS_STR, + IS_STR_ENUM, PassThrough, any_type, dict_of, @@ -139,6 +147,7 @@ class SamFunction(SamResourceMacro): """SAM function macro.""" resource_type = "AWS::Serverless::Function" + property_types = { "FunctionName": PropertyType(False, one_of(IS_STR, IS_DICT)), "Handler": PassThroughProperty(False), @@ -184,6 +193,10 @@ class SamFunction(SamResourceMacro): "LoggingConfig": PassThroughProperty(False), "RecursiveLoop": PassThroughProperty(False), "SourceKMSKeyArn": PassThroughProperty(False), + "CapacityProviderConfig": PropertyType(False, IS_DICT), + "FunctionScalingConfig": PropertyType(False, IS_DICT), + "VersionDeletionPolicy": PropertyType(False, IS_STR_ENUM(["Delete", "Retain"])), + "PublishToLatestPublished": PassThroughProperty(False), "TenancyConfig": PassThroughProperty(False), } @@ -229,6 +242,10 @@ class SamFunction(SamResourceMacro): LoggingConfig: Optional[Dict[str, Any]] RecursiveLoop: Optional[str] SourceKMSKeyArn: Optional[str] + CapacityProviderConfig: Optional[Dict[str, Any]] + FunctionScalingConfig: Optional[Dict[str, Any]] + PublishToLatestPublished: Optional[PassThrough] + VersionDeletionPolicy: Optional[Intrinsicable[str]] TenancyConfig: Optional[Dict[str, Any]] event_resolver = ResourceTypeResolver( @@ -254,6 +271,19 @@ class SamFunction(SamResourceMacro): "DestinationQueue": SQSQueue.resource_type, } + # Validation rules + __validation_rules__ = [ + (ValidationRule.MUTUALLY_EXCLUSIVE, ["CapacityProviderConfig", "ProvisionedConcurrencyConfig"]), + (ValidationRule.MUTUALLY_EXCLUSIVE, ["CapacityProviderConfig", "VpcConfig"]), + (ValidationRule.CONDITIONAL_REQUIREMENT, ["FunctionScalingConfig", "CapacityProviderConfig"]), + (ValidationRule.CONDITIONAL_REQUIREMENT, ["VersionDeletionPolicy", "AutoPublishAlias"]), + # TODO: To enable these rules, we need to update translator test input/output files to property configure template + # to avoid fail-fast. eg: test with DeploymentPreference without AutoPublishAlias would fail fast before reaching testing state + # (ValidationRule.MUTUALLY_EXCLUSIVE, ["ImageUri", "InlineCode", "CodeUri"]), + # (ValidationRule.CONDITIONAL_REQUIREMENT, ["DeploymentPreference", "AutoPublishAlias"]), + # (ValidationRule.CONDITIONAL_REQUIREMENT, ["ProvisionedConcurrencyConfig", "AutoPublishAlias"]), + ] + def resources_to_link(self, resources: Dict[str, Any]) -> Dict[str, Any]: try: return {"event_resources": self._event_resources_to_link(resources)} @@ -276,6 +306,11 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P conditions = kwargs.get("conditions", {}) feature_toggle = kwargs.get("feature_toggle") + # TODO: Skip pass schema_class=aws_serverless_function.Properties to skip schema validation for now. + # - adding this now would required update error message in error error_function_*_test.py + # - add this when we can verify that changing error message would not break customers + self.validate_before_transform(schema_class=None, collect_all_errors=False) + if self.DeadLetterQueue: self._validate_dlq(self.DeadLetterQueue) @@ -655,9 +690,64 @@ def _construct_lambda_function(self, intrinsics_resolver: IntrinsicsResolver) -> lambda_function.LoggingConfig = self.LoggingConfig lambda_function.TenancyConfig = self.TenancyConfig lambda_function.RecursiveLoop = self.RecursiveLoop + + # Transform capacity provider configuration + if self.CapacityProviderConfig: + lambda_function.CapacityProviderConfig = self._transform_capacity_provider_config() + + # Pass through function scaling configuration + if self.FunctionScalingConfig: + lambda_function.FunctionScalingConfig = self.FunctionScalingConfig + + # Pass through PublishToLatestPublished configuration + if self.PublishToLatestPublished is not None: + lambda_function.PublishToLatestPublished = self.PublishToLatestPublished + self._validate_package_type(lambda_function) return lambda_function + def _transform_capacity_provider_config(self) -> Dict[str, Any]: + """ + Transform SAM CapacityProviderConfig to CloudFormation format. + + Transforms from: + CapacityProviderConfig: + Arn: + PerExecutionEnvironmentMaxConcurrency: + ExecutionEnvironmentMemoryGiBPerVCpu: + + To: + CapacityProviderConfig: + LambdaManagedInstancesCapacityProviderConfig: + CapacityProviderArn: + PerExecutionEnvironmentMaxConcurrency: + ExecutionEnvironmentMemoryGiBPerVCpu: + """ + if not self.CapacityProviderConfig: + return {} + + # Validate CapacityProviderConfig using Pydantic model directly for comprehensive error collection + try: + validated_model = aws_serverless_function.CapacityProviderConfig.parse_obj(self.CapacityProviderConfig) + except Exception as e: + raise InvalidResourceException(self.logical_id, f"Invalid CapacityProviderConfig: {e!s}") from e + + # Extract validated properties - cast to Any to handle SamIntrinsicable types + capacity_provider_arn: Optional[SamIntrinsicable[str]] = validated_model.Arn + max_concurrency: Optional[SamIntrinsicable[int]] = validated_model.PerExecutionEnvironmentMaxConcurrency + memory_to_vcpu_ratio: Optional[SamIntrinsicable[float]] = validated_model.ExecutionEnvironmentMemoryGiBPerVCpu + + # Build the transformed structure + ec2_config: Dict[str, Any] = {"CapacityProviderArn": capacity_provider_arn} + + if max_concurrency is not None: + ec2_config["PerExecutionEnvironmentMaxConcurrency"] = max_concurrency + + if memory_to_vcpu_ratio is not None: + ec2_config["ExecutionEnvironmentMemoryGiBPerVCpu"] = memory_to_vcpu_ratio + + return {"LambdaManagedInstancesCapacityProviderConfig": ec2_config} + def _add_event_invoke_managed_policy( self, dest_config: Dict[str, Any], logical_id: str, dest_arn: Any ) -> Dict[str, Any]: @@ -934,6 +1024,20 @@ def _construct_inline_code(*args: Any, **kwargs: Dict[str, Any]) -> Dict[str, An code_dict["SourceKMSKeyArn"] = self.SourceKMSKeyArn return code_dict + def _get_default_version_deletion_policy(self) -> str: + """ + Determine the default DeletionPolicy for Lambda version resources. + + Returns: + str: "Delete" for functions with CapacityProviderConfig, + "Retain" for classic Lambda functions + """ + if self.CapacityProviderConfig is not None: + # LMI function - delete versions to avoid unnecessary costs + return DeletionPolicy.DELETE + # Classic Lambda function - retain versions (existing behavior) + return DeletionPolicy.RETAIN + def _construct_version( # noqa: PLR0912 self, function: LambdaFunction, @@ -1020,12 +1124,20 @@ def _construct_version( # noqa: PLR0912 attributes = self.get_passthrough_resource_attributes() if "DeletionPolicy" not in attributes: - attributes["DeletionPolicy"] = "Retain" + if self.VersionDeletionPolicy is not None: + # User explicitly specified VersionDeletionPolicy + attributes["DeletionPolicy"] = self.VersionDeletionPolicy + else: + # Use smart default based on function type + attributes["DeletionPolicy"] = self._get_default_version_deletion_policy() lambda_version = LambdaVersion(logical_id=logical_id, attributes=attributes) lambda_version.FunctionName = function.get_runtime_attr("name") lambda_version.Description = self.VersionDescription + if self.CapacityProviderConfig is not None and self.FunctionScalingConfig is not None: + lambda_version.FunctionScalingConfig = self.FunctionScalingConfig + return lambda_version def _construct_alias(self, name: str, function: LambdaFunction, version: LambdaVersion) -> LambdaAlias: @@ -1334,6 +1446,78 @@ def _construct_invoke_permission( return lambda_invoke_permission +class SamCapacityProvider(SamResourceMacro): + """ + SAM CapacityProvider resource transformer + """ + + resource_type = "AWS::Serverless::CapacityProvider" + resource_property_schema = aws_serverless_capacity_provider.Properties + property_types = { + "CapacityProviderName": Property(False, one_of(IS_STR, IS_DICT)), + "VpcConfig": Property(True, IS_DICT), + "OperatorRole": Property(False, one_of(IS_STR, IS_DICT)), + "Tags": Property(False, IS_DICT), + "PropagateTags": Property(False, IS_BOOL), + "InstanceRequirements": Property(False, IS_DICT), + "ScalingConfig": Property(False, IS_DICT), + "KMSKeyArn": Property(False, one_of(IS_STR, IS_DICT)), + } + + CapacityProviderName: Optional[Intrinsicable[str]] + VpcConfig: Dict[str, Any] + OperatorRole: Optional[PassThrough] + Tags: Optional[Dict[str, Any]] + PropagateTags: Optional[bool] + InstanceRequirements: Optional[Dict[str, Any]] + ScalingConfig: Optional[Dict[str, Any]] + KMSKeyArn: Optional[Intrinsicable[str]] + + # Validation rules + __validation_rules__ = [ + ( + ValidationRule.MUTUALLY_EXCLUSIVE, + ["InstanceRequirements.AllowedTypes", "InstanceRequirements.ExcludedTypes"], + ), + ] + + def to_cloudformation(self, **kwargs: Any) -> List[Resource]: + """ + Transform the SAM CapacityProvider resource to CloudFormation + """ + self.validate_before_transform(schema_class=self.resource_property_schema, collect_all_errors=True) + + # Use enhanced validation method with comprehensive error collection + model = self.validate_properties_and_return_model( + aws_serverless_capacity_provider.Properties, collect_all_errors=True + ) + + capacity_provider_generator = CapacityProviderGenerator( + logical_id=self.logical_id, + capacity_provider_name=passthrough_value(model.CapacityProviderName), + vpc_config=model.VpcConfig.dict() if model.VpcConfig else None, + operator_role=passthrough_value(model.OperatorRole), + tags=model.Tags, + instance_requirements=( + model.InstanceRequirements.dict(exclude_none=True) if model.InstanceRequirements else None + ), + scaling_config=model.ScalingConfig.dict() if model.ScalingConfig else None, + kms_key_arn=passthrough_value(model.KMSKeyArn), + depends_on=self.depends_on, + resource_attributes=self.resource_attributes, + passthrough_resource_attributes=self.get_passthrough_resource_attributes(), + ) + + resources = capacity_provider_generator.to_cloudformation() + + # Propagate tags to generated resources if PropagateTags is set. + # Need to combine tags with sam tags; Existing propagate_tags() method replace + # Tags assigned + self.propagate_tags_combine(resources, model.Tags, self.PropagateTags) + + return resources + + class SamApi(SamResourceMacro): """SAM rest API macro.""" @@ -1753,9 +1937,7 @@ class SamLayerVersion(SamResourceMacro): LicenseInfo: Optional[Intrinsicable[str]] RetentionPolicy: Optional[Intrinsicable[str]] - RETAIN = "Retain" - DELETE = "Delete" - retention_policy_options = [RETAIN, DELETE] + retention_policy_options = [DeletionPolicy.RETAIN, DeletionPolicy.DELETE] @cw_timer def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] @@ -1799,7 +1981,7 @@ def _construct_lambda_layer(self, intrinsics_resolver: IntrinsicsResolver) -> La attributes = self.get_passthrough_resource_attributes() if "DeletionPolicy" not in attributes: - attributes["DeletionPolicy"] = self.RETAIN + attributes["DeletionPolicy"] = DeletionPolicy.RETAIN if retention_policy_value is not None: attributes["DeletionPolicy"] = retention_policy_value @@ -1855,7 +2037,7 @@ def _get_retention_policy_value(self) -> Optional[str]: raise InvalidResourceException( self.logical_id, "'RetentionPolicy' does not accept intrinsic functions, " - f"please use one of the following options: {[self.RETAIN, self.DELETE]}", + f"please use one of the following options: {[DeletionPolicy.RETAIN, DeletionPolicy.DELETE]}", ) if self.RetentionPolicy is None: @@ -1865,7 +2047,7 @@ def _get_retention_policy_value(self) -> Optional[str]: raise InvalidResourceException( self.logical_id, "Invalid 'RetentionPolicy' type, " - f"please use one of the following options: {[self.RETAIN, self.DELETE]}", + f"please use one of the following options: {[DeletionPolicy.RETAIN, DeletionPolicy.DELETE]}", ) for option in self.retention_policy_options: @@ -1873,7 +2055,7 @@ def _get_retention_policy_value(self) -> Optional[str]: return option raise InvalidResourceException( self.logical_id, - f"'RetentionPolicy' must be one of the following options: {[self.RETAIN, self.DELETE]}.", + f"'RetentionPolicy' must be one of the following options: {[DeletionPolicy.RETAIN, DeletionPolicy.DELETE]}.", ) def _validate_architectures(self, lambda_layer: LambdaLayerVersion) -> None: @@ -1893,6 +2075,7 @@ def _validate_architectures(self, lambda_layer: LambdaLayerVersion) -> None: # Intrinsics are not validated if is_intrinsic(architectures): return + for arq in architectures: # We validate the values only if we they're not intrinsics if not is_intrinsic(arq) and arq not in [ARM64, X86_64]: diff --git a/samtranslator/model/types.py b/samtranslator/model/types.py index 5c86b8b15b..522def9a59 100644 --- a/samtranslator/model/types.py +++ b/samtranslator/model/types.py @@ -9,7 +9,7 @@ either a string or a list of strings, but do not validate whether the string(s) are valid IAM policy ARNs. """ -from typing import Any, Callable, Type, Union +from typing import Any, Callable, List, Type, Union import samtranslator.model.exceptions from samtranslator.internal.deprecation_control import deprecated @@ -138,6 +138,36 @@ def validate(value: Any, should_raise: bool = False) -> bool: return validate +def IS_STR_ENUM(valid_values: List[str]) -> Validator: + """Returns a validator function that succeeds only if the input is a string matching one of the valid enum values. + + :param list valid_values: the valid string values for the enum + :returns: a function which returns True if input is one of the valid string values, and raises TypeError otherwise + :rtype: callable + """ + + def validate(value: Any, should_raise: bool = True) -> bool: + if not isinstance(value, str): + if should_raise: + valid_values_str = ", ".join(f"'{v}'" for v in valid_values) + raise TypeError( + f"Expected a string value from [{valid_values_str}], but got type {type(value).__name__}." + ) + return False + + if value not in valid_values: + if should_raise: + valid_values_str = ", ".join(f"'{v}'" for v in valid_values) + raise TypeError(f"Expected one of [{valid_values_str}], but got '{value}'.") + return False + + return True + + # Attach enum values as an attribute for PropertyType to use + validate.enum_values = valid_values # type: ignore[attr-defined] + return validate + + @deprecated(replacement="IS_STR") def is_str() -> Validator: """ diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 341c67fc54..7e55420149 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -57,6 +57,10 @@ class Globals: "RecursiveLoop", "SourceKMSKeyArn", "TenancyConfig", + "CapacityProviderConfig", + "FunctionScalingConfig", + "PublishToLatestPublished", + "VersionDeletionPolicy", ], # Everything except # DefinitionBody: because its hard to reason about merge of Swagger dictionaries @@ -99,16 +103,27 @@ class Globals: SamResourceType.SimpleTable.value: ["SSESpecification"], SamResourceType.StateMachine.value: ["PropagateTags"], SamResourceType.LambdaLayerVersion.value: ["PublishLambdaVersion"], + SamResourceType.CapacityProvider.value: [ + "VpcConfig", + "OperatorRole", + "Tags", + "InstanceRequirements", + "ScalingConfig", + "KMSKeyArn", + "PropagateTags", + ], } # unreleased_properties *must be* part of supported_properties too unreleased_properties: Dict[str, List[str]] = { SamResourceType.Function.value: [ - "RuntimeManagementConfig", - "RecursiveLoop", - "SourceKMSKeyArn", "TenancyConfig", + "CapacityProviderConfig", + "FunctionScalingConfig", + "PublishToLatestPublished", + "VersionDeletionPolicy", ], } + unreleased_resource_types: List[str] = [SamResourceType.CapacityProvider.value] def __init__(self, template: Dict[str, Any]) -> None: """ @@ -117,7 +132,9 @@ def __init__(self, template: Dict[str, Any]) -> None: :param dict template: SAM template to be parsed """ self.supported_resource_section_names = [ - x.replace(self._RESOURCE_PREFIX, "") for x in self.supported_properties + x.replace(self._RESOURCE_PREFIX, "") + for x in self.supported_properties + if x not in self.unreleased_resource_types ] # Sort the names for stability in list ordering self.supported_resource_section_names.sort() diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 3df8ee7b6b..ed772bef11 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -273628,6 +273628,55 @@ "title": "Caching", "type": "object" }, + "CapacityProviderConfig": { + "additionalProperties": false, + "properties": { + "Arn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "The ARN of the capacity provider.\n*Type*: String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-capacityproviderarn) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "Arn" + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "number" + } + ], + "markdownDescription": "The memory in GiB per vCPU for the execution environment.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExecutionEnvironmentMemoryGiBPerVCpu`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-executionenvironmentmemorygibpervcpu) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "ExecutionEnvironmentMemoryGiBPerVCpu" + }, + "PerExecutionEnvironmentMaxConcurrency": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + } + ], + "markdownDescription": "The maximum concurrency for the execution environment.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`PerExecutionEnvironmentMaxConcurrency`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-perexecutionenvironmentmaxconcurrency) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "PerExecutionEnvironmentMaxConcurrency" + } + }, + "required": [ + "Arn" + ], + "title": "CapacityProviderConfig", + "type": "object" + }, "CloudWatchLogsEvent": { "additionalProperties": false, "properties": { @@ -275014,6 +275063,58 @@ "title": "HttpApiEventProperties", "type": "object" }, + "InstanceRequirements": { + "additionalProperties": false, + "properties": { + "AllowedTypes": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The allowed instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`AllowedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-allowedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "AllowedTypes", + "type": "array" + }, + "Architectures": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The CPU architecture for the instances.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Architecture`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-architecture) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "Architectures", + "type": "array" + }, + "ExcludedTypes": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The excluded instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExcludedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-excludedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "ExcludedTypes", + "type": "array" + } + }, + "title": "InstanceRequirements", + "type": "object" + }, "IoTRuleEvent": { "additionalProperties": false, "properties": { @@ -276512,6 +276613,37 @@ "title": "SQSEventProperties", "type": "object" }, + "ScalingConfig": { + "additionalProperties": false, + "properties": { + "AverageCPUUtilization": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "number" + } + ], + "markdownDescription": "A target tracking scaling policy based on average CPU utilization. Lambda will automatically adjusts the capacity provider's compute resources to this a specified target value.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is transformed to a scaling policy with `PredefinedMetricType` of `LambdaCapacityProviderAverageCPUUtilization`.", + "title": "AverageCPUUtilization" + }, + "MaxVCpuCount": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + } + ], + "markdownDescription": "The maximum number of compute instances that the capacity provider can scale up to.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaxVCpuCount`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-capacityproviderscalingconfig.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig-maxvcpucount) property of the `AWS::Lambda::CapacityProvider` `CapacityProviderScalingConfig` data type.", + "title": "MaxVCpuCount" + } + }, + "title": "ScalingConfig", + "type": "object" + }, "ScheduleEventProperties": { "additionalProperties": false, "properties": { @@ -276979,12 +277111,55 @@ "title": "UserPoolConfig", "type": "object" }, + "VpcConfig": { + "additionalProperties": false, + "properties": { + "SecurityGroupIds": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "A list of VPC security group IDs.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityGroupIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-securitygroupids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type.", + "title": "SecurityGroupIds", + "type": "array" + }, + "SubnetIds": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "A list of VPC subnet IDs.\n*Type*: List of String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SubnetIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-subnetids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type.", + "title": "SubnetIds", + "type": "array" + } + }, + "required": [ + "SubnetIds" + ], + "title": "VpcConfig", + "type": "object" + }, "__main____Globals": { "additionalProperties": false, "properties": { "Api": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_api__Globals" }, + "CapacityProvider": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Globals" + }, "Function": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_function__Globals" }, @@ -277939,6 +278114,174 @@ "title": "Resource", "type": "object" }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Globals": { + "additionalProperties": false, + "properties": { + "InstanceRequirements": { + "allOf": [ + { + "$ref": "#/definitions/InstanceRequirements" + } + ], + "markdownDescription": "Instance requirements for the capacity provider.\n*Type*: [InstanceRequirements](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-instancerequirements.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`InstanceRequirements`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-instancerequirements) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "InstanceRequirements" + }, + "KMSKeyArn": { + "$ref": "#/definitions/PassThroughProp" + }, + "OperatorRole": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the capacity provider operator role. If not provided, SAM auto-generates one with EC2 management permissions.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderOperatorRoleArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-permissionsconfig.html#cfn-lambda-capacityprovider-permissionsconfig-capacityprovideroperatorrolearn) property of the `AWS::Lambda::CapacityProvider` `PermissionsConfig` data type.", + "title": "OperatorRole" + }, + "PropagateTags": { + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-capacityprovider.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "PropagateTags", + "type": "boolean" + }, + "ScalingConfig": { + "allOf": [ + { + "$ref": "#/definitions/ScalingConfig" + } + ], + "markdownDescription": "Scaling configuration for the capacity provider.\n*Type*: [ScalingConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-scalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "ScalingConfig" + }, + "Tags": { + "markdownDescription": "A map of key-value pairs to apply to the capacity provider.\n*Type*: Map\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-tags) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "Tags", + "type": "object" + }, + "VpcConfig": { + "allOf": [ + { + "$ref": "#/definitions/VpcConfig" + } + ], + "markdownDescription": "VPC configuration for the capacity provider.\n*Type*: [VpcConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-vpcconfig.html)\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-vpcconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "VpcConfig" + } + }, + "title": "Globals", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Properties": { + "additionalProperties": false, + "properties": { + "CapacityProviderName": { + "$ref": "#/definitions/PassThroughProp" + }, + "InstanceRequirements": { + "allOf": [ + { + "$ref": "#/definitions/InstanceRequirements" + } + ], + "markdownDescription": "Instance requirements for the capacity provider.\n*Type*: [InstanceRequirements](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-instancerequirements.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`InstanceRequirements`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-instancerequirements) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "InstanceRequirements" + }, + "KMSKeyArn": { + "$ref": "#/definitions/PassThroughProp" + }, + "OperatorRole": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the capacity provider operator role. If not provided, SAM auto-generates one with EC2 management permissions.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderOperatorRoleArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-permissionsconfig.html#cfn-lambda-capacityprovider-permissionsconfig-capacityprovideroperatorrolearn) property of the `AWS::Lambda::CapacityProvider` `PermissionsConfig` data type.", + "title": "OperatorRole" + }, + "PropagateTags": { + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-capacityprovider.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "PropagateTags", + "type": "boolean" + }, + "ScalingConfig": { + "allOf": [ + { + "$ref": "#/definitions/ScalingConfig" + } + ], + "markdownDescription": "Scaling configuration for the capacity provider.\n*Type*: [ScalingConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-scalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "ScalingConfig" + }, + "Tags": { + "markdownDescription": "A map of key-value pairs to apply to the capacity provider.\n*Type*: Map\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-tags) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "Tags", + "type": "object" + }, + "VpcConfig": { + "allOf": [ + { + "$ref": "#/definitions/VpcConfig" + } + ], + "markdownDescription": "VPC configuration for the capacity provider.\n*Type*: [VpcConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-vpcconfig.html)\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-vpcconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "VpcConfig" + } + }, + "required": [ + "VpcConfig" + ], + "title": "Properties", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Resource": { + "additionalProperties": false, + "properties": { + "Condition": { + "$ref": "#/definitions/PassThroughProp" + }, + "DeletionPolicy": { + "$ref": "#/definitions/PassThroughProp" + }, + "DependsOn": { + "$ref": "#/definitions/PassThroughProp" + }, + "IgnoreGlobals": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Ignoreglobals" + }, + "Metadata": { + "$ref": "#/definitions/PassThroughProp" + }, + "Properties": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Properties" + }, + "Type": { + "enum": [ + "AWS::Serverless::CapacityProvider" + ], + "title": "Type", + "type": "string" + }, + "UpdateReplacePolicy": { + "$ref": "#/definitions/PassThroughProp" + } + }, + "required": [ + "Type", + "Properties" + ], + "title": "Resource", + "type": "object" + }, "samtranslator__internal__schema_source__aws_serverless_connector__Properties": { "additionalProperties": false, "properties": { @@ -278411,6 +278754,15 @@ "markdownDescription": "The name of the Lambda alias\\. For more information about Lambda aliases, see [Lambda function aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) in the *AWS Lambda Developer Guide*\\. For examples that use this property, see [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\. \nAWS SAM generates [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html) and [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html) resources when this property is set\\. For information about this scenario, see [AutoPublishAlias property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-function.html#sam-specification-generated-resources-function-autopublishalias)\\. For general information about generated AWS CloudFormation resources, see [Generated AWS CloudFormation resources for AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources.html)\\. \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\\.", "title": "AutoPublishAlias" }, + "CapacityProviderConfig": { + "allOf": [ + { + "$ref": "#/definitions/CapacityProviderConfig" + } + ], + "markdownDescription": "Configuration for using a Lambda capacity provider with this function.\n*Type*: [CapacityProviderConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-capacityproviderconfig.html)\n*Required*", + "title": "CapacityProviderConfig" + }, "CodeUri": { "anyOf": [ { @@ -278472,6 +278824,9 @@ "markdownDescription": "The object that describes event invoke configuration on a Lambda function\\. \n*Type*: [EventInvokeConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-eventinvokeconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "EventInvokeConfig" }, + "FunctionScalingConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Handler": { "markdownDescription": "The function within your code that is called to begin execution\\. This property is only required if the `PackageType` property is set to `Zip`\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Handler`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-handler) property of an `AWS::Lambda::Function` resource\\.", "title": "Handler", @@ -278526,6 +278881,20 @@ "markdownDescription": "The provisioned concurrency configuration of a function's alias\\. \n`ProvisionedConcurrencyConfig` can be specified only if the `AutoPublishAlias` is set\\. Otherwise, an error results\\.\n*Type*: [ProvisionedConcurrencyConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ProvisionedConcurrencyConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) property of an `AWS::Lambda::Alias` resource\\.", "title": "ProvisionedConcurrencyConfig" }, + "PublishToLatestPublished": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "title": "Publishtolatestpublished" + }, "RecursiveLoop": { "$ref": "#/definitions/PassThroughProp" }, @@ -278603,6 +278972,21 @@ "markdownDescription": "The string that specifies the function's X\\-Ray tracing mode\\. \n+ `Active` \u2013 Activates X\\-Ray tracing for the function\\.\n+ `Disabled` \u2013 Deactivates X\\-Ray for the function\\.\n+ `PassThrough` \u2013 Activates X\\-Ray tracing for the function\\. Sampling decision is delegated to the downstream services\\.\nIf specified as `Active` or `PassThrough` and the `Role` property is not set, AWS SAM adds the `arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess` policy to the Lambda execution role that it creates for you\\. \nFor more information about X\\-Ray, see [Using AWS Lambda with AWS X\\-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) in the *AWS Lambda Developer Guide*\\. \n*Valid values*: \\[`Active`\\|`Disabled`\\|`PassThrough`\\] \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`TracingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-tracingconfig) property of an `AWS::Lambda::Function` resource\\.", "title": "Tracing" }, + "VersionDeletionPolicy": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "markdownDescription": "Policy for deleting old versions of the function. This will set [DeletionPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html) attribute for the version resource when use with AutoPublishAlias\n*Type*: String\n*Required*: No\n*Valid values*: `Retain` or `Delete`\n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.", + "title": "VersionDeletionPolicy" + }, "VpcConfig": { "allOf": [ { @@ -278661,6 +279045,15 @@ "markdownDescription": "When used, this string works with the `CodeUri` value to determine if a new Lambda version needs to be published\\. This property is often used to resolve the following deployment issue: A deployment package is stored in an Amazon S3 location and is replaced by a new deployment package with updated Lambda function code but the `CodeUri` property remains unchanged \\(as opposed to the new deployment package being uploaded to a new Amazon S3 location and the `CodeUri` being changed to the new location\\)\\. \nThis problem is marked by an AWS SAM template having the following characteristics: \n+ The `DeploymentPreference` object is configured for gradual deployments \\(as described in [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\)\n+ The `AutoPublishAlias` property is set and doesn't change between deployments\n+ The `CodeUri` property is set and doesn't change between deployments\\.\nIn this scenario, updating `AutoPublishCodeSha256` results in a new Lambda version being created successfully\\. However, new function code deployed to Amazon S3 will not be recognized\\. To recognize new function code, consider using versioning in your Amazon S3 bucket\\. Specify the `Version` property for your Lambda function and configure your bucket to always use the latest deployment package\\. \nIn this scenario, to trigger the gradual deployment successfully, you must provide a unique value for `AutoPublishCodeSha256`\\. \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\\.", "title": "AutoPublishCodeSha256" }, + "CapacityProviderConfig": { + "allOf": [ + { + "$ref": "#/definitions/CapacityProviderConfig" + } + ], + "markdownDescription": "Configuration for using a Lambda capacity provider with this function.\n*Type*: [CapacityProviderConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-capacityproviderconfig.html)\n*Required*", + "title": "CapacityProviderConfig" + }, "CodeSigningConfigArn": { "markdownDescription": "The ARN of the [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html) resource, used to enable code signing for this function\\. For more information about code signing, see [Set up code signing for your AWS SAM application](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/authoring-codesigning.html)\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CodeSigningConfigArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-codesigningconfigarn) property of an `AWS::Lambda::Function` resource\\.", "title": "CodeSigningConfigArn", @@ -278802,6 +279195,9 @@ "title": "FunctionName", "type": "string" }, + "FunctionScalingConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "FunctionUrlConfig": { "allOf": [ { @@ -278914,6 +279310,20 @@ "markdownDescription": "The provisioned concurrency configuration of a function's alias\\. \n`ProvisionedConcurrencyConfig` can be specified only if the `AutoPublishAlias` is set\\. Otherwise, an error results\\.\n*Type*: [ProvisionedConcurrencyConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ProvisionedConcurrencyConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) property of an `AWS::Lambda::Alias` resource\\.", "title": "ProvisionedConcurrencyConfig" }, + "PublishToLatestPublished": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "title": "Publishtolatestpublished" + }, "RecursiveLoop": { "$ref": "#/definitions/PassThroughProp" }, @@ -279003,6 +279413,21 @@ "markdownDescription": "The string that specifies the function's X\\-Ray tracing mode\\. \n+ `Active` \u2013 Activates X\\-Ray tracing for the function\\.\n+ `Disabled` \u2013 Deactivates X\\-Ray for the function\\.\n+ `PassThrough` \u2013 Activates X\\-Ray tracing for the function\\. Sampling decision is delegated to the downstream services\\.\nIf specified as `Active` or `PassThrough` and the `Role` property is not set, AWS SAM adds the `arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess` policy to the Lambda execution role that it creates for you\\. \nFor more information about X\\-Ray, see [Using AWS Lambda with AWS X\\-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) in the *AWS Lambda Developer Guide*\\. \n*Valid values*: \\[`Active`\\|`Disabled`\\|`PassThrough`\\] \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`TracingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-tracingconfig) property of an `AWS::Lambda::Function` resource\\.", "title": "Tracing" }, + "VersionDeletionPolicy": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "markdownDescription": "Policy for deleting old versions of the function. This will set [DeletionPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html) attribute for the version resource when use with AutoPublishAlias\n*Type*: String\n*Required*: No\n*Valid values*: `Retain` or `Delete`\n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.", + "title": "VersionDeletionPolicy" + }, "VersionDescription": { "allOf": [ { @@ -281352,6 +281777,9 @@ { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_graphqlapi__Resource" }, + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Resource" + }, { "$ref": "#/definitions/AWS::ACMPCA::Certificate" }, diff --git a/samtranslator/sdk/resource.py b/samtranslator/sdk/resource.py index fbadd006c2..c0106b0b64 100644 --- a/samtranslator/sdk/resource.py +++ b/samtranslator/sdk/resource.py @@ -69,6 +69,7 @@ class SamResourceType(Enum): LambdaLayerVersion = "AWS::Serverless::LayerVersion" HttpApi = "AWS::Serverless::HttpApi" StateMachine = "AWS::Serverless::StateMachine" + CapacityProvider = "AWS::Serverless::CapacityProvider" @classmethod def has_value(cls, value: str) -> bool: diff --git a/samtranslator/translator/verify_logical_id.py b/samtranslator/translator/verify_logical_id.py index 510995a83b..473c9e5368 100644 --- a/samtranslator/translator/verify_logical_id.py +++ b/samtranslator/translator/verify_logical_id.py @@ -6,6 +6,7 @@ # type_after_transform: type_before_transform "AWS::Lambda::Function": "AWS::Serverless::Function", "AWS::Lambda::LayerVersion": "AWS::Serverless::LayerVersion", + "AWS::Lambda::CapacityProvider": "AWS::Serverless::CapacityProvider", "AWS::ApiGateway::RestApi": "AWS::Serverless::Api", "AWS::ApiGatewayV2::Api": "AWS::Serverless::HttpApi", "AWS::S3::Bucket": "AWS::S3::Bucket", diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index e366c0c3a8..cd4da3d882 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -196,6 +196,55 @@ "title": "Caching", "type": "object" }, + "CapacityProviderConfig": { + "additionalProperties": false, + "properties": { + "Arn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "The ARN of the capacity provider.\n*Type*: String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-capacityproviderarn) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "Arn" + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "number" + } + ], + "markdownDescription": "The memory in GiB per vCPU for the execution environment.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExecutionEnvironmentMemoryGiBPerVCpu`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-executionenvironmentmemorygibpervcpu) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "ExecutionEnvironmentMemoryGiBPerVCpu" + }, + "PerExecutionEnvironmentMaxConcurrency": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + } + ], + "markdownDescription": "The maximum concurrency for the execution environment.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`PerExecutionEnvironmentMaxConcurrency`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-capacityproviderconfig.html#cfn-lambda-function-capacityproviderconfig-perexecutionenvironmentmaxconcurrency) property of the `AWS::Lambda::Function` `CapacityProviderConfig` data type.", + "title": "PerExecutionEnvironmentMaxConcurrency" + } + }, + "required": [ + "Arn" + ], + "title": "CapacityProviderConfig", + "type": "object" + }, "CloudWatchLogsEvent": { "additionalProperties": false, "properties": { @@ -1633,6 +1682,58 @@ "title": "HttpApiEventProperties", "type": "object" }, + "InstanceRequirements": { + "additionalProperties": false, + "properties": { + "AllowedTypes": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The allowed instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`AllowedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-allowedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "AllowedTypes", + "type": "array" + }, + "Architectures": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The CPU architecture for the instances.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Architecture`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-architecture) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "Architectures", + "type": "array" + }, + "ExcludedTypes": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "The excluded instance types.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`ExcludedInstanceTypes`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-instancerequirements.html#cfn-lambda-capacityprovider-instancerequirements-excludedinstancetypes) property of the `AWS::Lambda::CapacityProvider` `InstanceRequirements` data type.", + "title": "ExcludedTypes", + "type": "array" + } + }, + "title": "InstanceRequirements", + "type": "object" + }, "IoTRuleEvent": { "additionalProperties": false, "properties": { @@ -3062,6 +3163,37 @@ "title": "SQSEventProperties", "type": "object" }, + "ScalingConfig": { + "additionalProperties": false, + "properties": { + "AverageCPUUtilization": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "number" + } + ], + "markdownDescription": "A target tracking scaling policy based on average CPU utilization. Lambda will automatically adjusts the capacity provider's compute resources to this a specified target value.\n*Type*: Number\n*Required*: No\n*AWS CloudFormation compatibility*: This property is transformed to a scaling policy with `PredefinedMetricType` of `LambdaCapacityProviderAverageCPUUtilization`.", + "title": "AverageCPUUtilization" + }, + "MaxVCpuCount": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + } + ], + "markdownDescription": "The maximum number of compute instances that the capacity provider can scale up to.\n*Type*: Integer\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`MaxVCpuCount`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-capacityproviderscalingconfig.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig-maxvcpucount) property of the `AWS::Lambda::CapacityProvider` `CapacityProviderScalingConfig` data type.", + "title": "MaxVCpuCount" + } + }, + "title": "ScalingConfig", + "type": "object" + }, "ScheduleEventProperties": { "additionalProperties": false, "properties": { @@ -3513,12 +3645,55 @@ "title": "UserPoolConfig", "type": "object" }, + "VpcConfig": { + "additionalProperties": false, + "properties": { + "SecurityGroupIds": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "A list of VPC security group IDs.\n*Type*: List of String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityGroupIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-securitygroupids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type.", + "title": "SecurityGroupIds", + "type": "array" + }, + "SubnetIds": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + }, + "markdownDescription": "A list of VPC subnet IDs.\n*Type*: List of String\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`SubnetIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-vpcconfig.html#cfn-lambda-capacityprovider-vpcconfig-subnetids) property of the `AWS::Lambda::CapacityProvider` `VpcConfig` data type.", + "title": "SubnetIds", + "type": "array" + } + }, + "required": [ + "SubnetIds" + ], + "title": "VpcConfig", + "type": "object" + }, "__main____Globals": { "additionalProperties": false, "properties": { "Api": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_api__Globals" }, + "CapacityProvider": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Globals" + }, "Function": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_function__Globals" }, @@ -4951,6 +5126,174 @@ "title": "Resource", "type": "object" }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Globals": { + "additionalProperties": false, + "properties": { + "InstanceRequirements": { + "allOf": [ + { + "$ref": "#/definitions/InstanceRequirements" + } + ], + "markdownDescription": "Instance requirements for the capacity provider.\n*Type*: [InstanceRequirements](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-instancerequirements.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`InstanceRequirements`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-instancerequirements) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "InstanceRequirements" + }, + "KMSKeyArn": { + "$ref": "#/definitions/PassThroughProp" + }, + "OperatorRole": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the capacity provider operator role. If not provided, SAM auto-generates one with EC2 management permissions.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderOperatorRoleArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-permissionsconfig.html#cfn-lambda-capacityprovider-permissionsconfig-capacityprovideroperatorrolearn) property of the `AWS::Lambda::CapacityProvider` `PermissionsConfig` data type.", + "title": "OperatorRole" + }, + "PropagateTags": { + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-capacityprovider.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "PropagateTags", + "type": "boolean" + }, + "ScalingConfig": { + "allOf": [ + { + "$ref": "#/definitions/ScalingConfig" + } + ], + "markdownDescription": "Scaling configuration for the capacity provider.\n*Type*: [ScalingConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-scalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "ScalingConfig" + }, + "Tags": { + "markdownDescription": "A map of key-value pairs to apply to the capacity provider.\n*Type*: Map\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-tags) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "Tags", + "type": "object" + }, + "VpcConfig": { + "allOf": [ + { + "$ref": "#/definitions/VpcConfig" + } + ], + "markdownDescription": "VPC configuration for the capacity provider.\n*Type*: [VpcConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-vpcconfig.html)\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-vpcconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "VpcConfig" + } + }, + "title": "Globals", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Properties": { + "additionalProperties": false, + "properties": { + "CapacityProviderName": { + "$ref": "#/definitions/PassThroughProp" + }, + "InstanceRequirements": { + "allOf": [ + { + "$ref": "#/definitions/InstanceRequirements" + } + ], + "markdownDescription": "Instance requirements for the capacity provider.\n*Type*: [InstanceRequirements](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-instancerequirements.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`InstanceRequirements`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-instancerequirements) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "InstanceRequirements" + }, + "KMSKeyArn": { + "$ref": "#/definitions/PassThroughProp" + }, + "OperatorRole": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the capacity provider operator role. If not provided, SAM auto-generates one with EC2 management permissions.\n*Type*: String\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderOperatorRoleArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-capacityprovider-permissionsconfig.html#cfn-lambda-capacityprovider-permissionsconfig-capacityprovideroperatorrolearn) property of the `AWS::Lambda::CapacityProvider` `PermissionsConfig` data type.", + "title": "OperatorRole" + }, + "PropagateTags": { + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-capacityprovider.html) generated resources\\. Specify `True` to propagate tags in your generated resources\\. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "PropagateTags", + "type": "boolean" + }, + "ScalingConfig": { + "allOf": [ + { + "$ref": "#/definitions/ScalingConfig" + } + ], + "markdownDescription": "Scaling configuration for the capacity provider.\n*Type*: [ScalingConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-scalingconfig.html)\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`CapacityProviderScalingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-capacityproviderscalingconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "ScalingConfig" + }, + "Tags": { + "markdownDescription": "A map of key-value pairs to apply to the capacity provider.\n*Type*: Map\n*Required*: No\n*AWS CloudFormation compatibility*: This property is passed directly to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-tags) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "Tags", + "type": "object" + }, + "VpcConfig": { + "allOf": [ + { + "$ref": "#/definitions/VpcConfig" + } + ], + "markdownDescription": "VPC configuration for the capacity provider.\n*Type*: [VpcConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-capacityprovider-vpcconfig.html)\n*Required*: Yes\n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-capacityprovider.html#cfn-lambda-capacityprovider-vpcconfig) property of an `AWS::Lambda::CapacityProvider` resource.", + "title": "VpcConfig" + } + }, + "required": [ + "VpcConfig" + ], + "title": "Properties", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_capacity_provider__Resource": { + "additionalProperties": false, + "properties": { + "Condition": { + "$ref": "#/definitions/PassThroughProp" + }, + "DeletionPolicy": { + "$ref": "#/definitions/PassThroughProp" + }, + "DependsOn": { + "$ref": "#/definitions/PassThroughProp" + }, + "IgnoreGlobals": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Ignoreglobals" + }, + "Metadata": { + "$ref": "#/definitions/PassThroughProp" + }, + "Properties": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Properties" + }, + "Type": { + "enum": [ + "AWS::Serverless::CapacityProvider" + ], + "title": "Type", + "type": "string" + }, + "UpdateReplacePolicy": { + "$ref": "#/definitions/PassThroughProp" + } + }, + "required": [ + "Type", + "Properties" + ], + "title": "Resource", + "type": "object" + }, "samtranslator__internal__schema_source__aws_serverless_connector__Properties": { "additionalProperties": false, "properties": { @@ -5434,6 +5777,15 @@ "markdownDescription": "The name of the Lambda alias\\. For more information about Lambda aliases, see [Lambda function aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) in the *AWS Lambda Developer Guide*\\. For examples that use this property, see [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\. \nAWS SAM generates [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html) and [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html) resources when this property is set\\. For information about this scenario, see [AutoPublishAlias property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-function.html#sam-specification-generated-resources-function-autopublishalias)\\. For general information about generated AWS CloudFormation resources, see [Generated AWS CloudFormation resources for AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources.html)\\. \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\\.", "title": "AutoPublishAlias" }, + "CapacityProviderConfig": { + "allOf": [ + { + "$ref": "#/definitions/CapacityProviderConfig" + } + ], + "markdownDescription": "Configuration for using a Lambda capacity provider with this function.\n*Type*: [CapacityProviderConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-capacityproviderconfig.html)\n*Required*", + "title": "CapacityProviderConfig" + }, "CodeUri": { "anyOf": [ { @@ -5523,6 +5875,9 @@ "markdownDescription": "The object that describes event invoke configuration on a Lambda function\\. \n*Type*: [EventInvokeConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-eventinvokeconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "EventInvokeConfig" }, + "FunctionScalingConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Handler": { "__samPassThrough": { "markdownDescriptionOverride": "The function within your code that is called to begin execution\\. This property is only required if the `PackageType` property is set to `Zip`\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Handler`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-handler) property of an `AWS::Lambda::Function` resource\\.", @@ -5605,6 +5960,20 @@ "markdownDescription": "The provisioned concurrency configuration of a function's alias\\. \n`ProvisionedConcurrencyConfig` can be specified only if the `AutoPublishAlias` is set\\. Otherwise, an error results\\.\n*Type*: [ProvisionedConcurrencyConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`ProvisionedConcurrencyConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html#cfn-lambda-alias-provisionedconcurrencyconfig) property of an `AWS::Lambda::Alias` resource\\.", "title": "ProvisionedConcurrencyConfig" }, + "PublishToLatestPublished": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "title": "Publishtolatestpublished" + }, "RecursiveLoop": { "$ref": "#/definitions/PassThroughProp" }, @@ -5710,6 +6079,21 @@ "markdownDescription": "The string that specifies the function's X\\-Ray tracing mode\\. \n+ `Active` \u2013 Activates X\\-Ray tracing for the function\\.\n+ `Disabled` \u2013 Deactivates X\\-Ray for the function\\.\n+ `PassThrough` \u2013 Activates X\\-Ray tracing for the function\\. Sampling decision is delegated to the downstream services\\.\nIf specified as `Active` or `PassThrough` and the `Role` property is not set, AWS SAM adds the `arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess` policy to the Lambda execution role that it creates for you\\. \nFor more information about X\\-Ray, see [Using AWS Lambda with AWS X\\-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) in the *AWS Lambda Developer Guide*\\. \n*Valid values*: \\[`Active`\\|`Disabled`\\|`PassThrough`\\] \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`TracingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-tracingconfig) property of an `AWS::Lambda::Function` resource\\.", "title": "Tracing" }, + "VersionDeletionPolicy": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "markdownDescription": "Policy for deleting old versions of the function. This will set [DeletionPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html) attribute for the version resource when use with AutoPublishAlias\n*Type*: String\n*Required*: No\n*Valid values*: `Retain` or `Delete`\n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.", + "title": "VersionDeletionPolicy" + }, "VpcConfig": { "allOf": [ { @@ -5779,6 +6163,15 @@ "markdownDescription": "When used, this string works with the `CodeUri` value to determine if a new Lambda version needs to be published\\. This property is often used to resolve the following deployment issue: A deployment package is stored in an Amazon S3 location and is replaced by a new deployment package with updated Lambda function code but the `CodeUri` property remains unchanged \\(as opposed to the new deployment package being uploaded to a new Amazon S3 location and the `CodeUri` being changed to the new location\\)\\. \nThis problem is marked by an AWS SAM template having the following characteristics: \n+ The `DeploymentPreference` object is configured for gradual deployments \\(as described in [Deploying serverless applications gradually with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)\\)\n+ The `AutoPublishAlias` property is set and doesn't change between deployments\n+ The `CodeUri` property is set and doesn't change between deployments\\.\nIn this scenario, updating `AutoPublishCodeSha256` results in a new Lambda version being created successfully\\. However, new function code deployed to Amazon S3 will not be recognized\\. To recognize new function code, consider using versioning in your Amazon S3 bucket\\. Specify the `Version` property for your Lambda function and configure your bucket to always use the latest deployment package\\. \nIn this scenario, to trigger the gradual deployment successfully, you must provide a unique value for `AutoPublishCodeSha256`\\. \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\\.", "title": "AutoPublishCodeSha256" }, + "CapacityProviderConfig": { + "allOf": [ + { + "$ref": "#/definitions/CapacityProviderConfig" + } + ], + "markdownDescription": "Configuration for using a Lambda capacity provider with this function.\n*Type*: [CapacityProviderConfig](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-capacityproviderconfig.html)\n*Required*", + "title": "CapacityProviderConfig" + }, "CodeSigningConfigArn": { "__samPassThrough": { "markdownDescriptionOverride": "The ARN of the [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-codesigningconfig.html) resource, used to enable code signing for this function\\. For more information about code signing, see [Set up code signing for your AWS SAM application](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/authoring-codesigning.html)\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CodeSigningConfigArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-codesigningconfigarn) property of an `AWS::Lambda::Function` resource\\.", @@ -6004,6 +6397,9 @@ ], "title": "FunctionName" }, + "FunctionScalingConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "FunctionUrlConfig": { "allOf": [ { @@ -6184,6 +6580,20 @@ ], "title": "ProvisionedConcurrencyConfig" }, + "PublishToLatestPublished": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "title": "Publishtolatestpublished" + }, "RecursiveLoop": { "$ref": "#/definitions/PassThroughProp" }, @@ -6301,6 +6711,21 @@ "markdownDescription": "The string that specifies the function's X\\-Ray tracing mode\\. \n+ `Active` \u2013 Activates X\\-Ray tracing for the function\\.\n+ `Disabled` \u2013 Deactivates X\\-Ray for the function\\.\n+ `PassThrough` \u2013 Activates X\\-Ray tracing for the function\\. Sampling decision is delegated to the downstream services\\.\nIf specified as `Active` or `PassThrough` and the `Role` property is not set, AWS SAM adds the `arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess` policy to the Lambda execution role that it creates for you\\. \nFor more information about X\\-Ray, see [Using AWS Lambda with AWS X\\-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) in the *AWS Lambda Developer Guide*\\. \n*Valid values*: \\[`Active`\\|`Disabled`\\|`PassThrough`\\] \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`TracingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-tracingconfig) property of an `AWS::Lambda::Function` resource\\.", "title": "Tracing" }, + "VersionDeletionPolicy": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "markdownDescription": "Policy for deleting old versions of the function. This will set [DeletionPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html) attribute for the version resource when use with AutoPublishAlias\n*Type*: String\n*Required*: No\n*Valid values*: `Retain` or `Delete`\n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.", + "title": "VersionDeletionPolicy" + }, "VersionDescription": { "allOf": [ { @@ -8703,6 +9128,9 @@ { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_graphqlapi__Resource" }, + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_capacity_provider__Resource" + }, { "$ref": "#/definitions/samtranslator__internal__schema_source__any_cfn_resource__Resource" } diff --git a/tests/model/capacity_provider/__init__.py b/tests/model/capacity_provider/__init__.py new file mode 100644 index 0000000000..f0b712809f --- /dev/null +++ b/tests/model/capacity_provider/__init__.py @@ -0,0 +1 @@ +# Tests for the capacity provider model components diff --git a/tests/model/capacity_provider/test_generators.py b/tests/model/capacity_provider/test_generators.py new file mode 100644 index 0000000000..11f6d784b0 --- /dev/null +++ b/tests/model/capacity_provider/test_generators.py @@ -0,0 +1,224 @@ +from typing import List +from unittest import TestCase +from unittest.mock import patch + +from samtranslator.model import Resource +from samtranslator.model.capacity_provider.generators import CapacityProviderGenerator +from samtranslator.model.capacity_provider.resources import LambdaCapacityProvider +from samtranslator.model.intrinsics import fnGetAtt + +# SAM should generate +# - CapacityProvider +# - OperatorRole +EXECPTED_SAM_AUTO_GENERATED_RESOURCES = 2 + + +class TestCapacityProviderGenerator(TestCase): + + def setUp(self): + self.logical_id = "MyCapacityProvider" + self.vpc_config = {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + self.operator_role = "arn:aws:iam::123456789012:role/test" + self.tags = {"Environment": "Production"} + self.instance_requirements = { + "Architectures": ["arm64"], + "AllowedTypes": ["c5.xlarge"], + "ExcludedTypes": ["t2.micro"], + } + self.scaling_config = { + "MaxVCpuCount": 10, + "AverageCPUUtilization": 70.0, + } + self.kms_key_arn = "arn:aws:kms:us-west-2:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456" + self.depends_on = ["AnotherResource"] + self.resource_attributes = {"DeletionPolicy": "Retain"} + self.passthrough_resource_attributes = {"Condition": "MyCondition"} + + def test_init(self): + """Test initialization of CapacityProviderGenerator""" + generator = CapacityProviderGenerator( + self.logical_id, + capacity_provider_name="test-provider", + vpc_config=self.vpc_config, + operator_role=self.operator_role, + tags=self.tags, + instance_requirements=self.instance_requirements, + scaling_config=self.scaling_config, + kms_key_arn=self.kms_key_arn, + depends_on=self.depends_on, + resource_attributes=self.resource_attributes, + passthrough_resource_attributes=self.passthrough_resource_attributes, + ) + + self.assertEqual(generator.logical_id, self.logical_id) + self.assertEqual(generator.capacity_provider_name, "test-provider") + self.assertEqual(generator.vpc_config, self.vpc_config) + self.assertEqual(generator.operator_role, self.operator_role) + self.assertEqual(generator.tags, self.tags) + self.assertEqual(generator.instance_requirements, self.instance_requirements) + self.assertEqual(generator.scaling_config, self.scaling_config) + self.assertEqual(generator.kms_key_arn, self.kms_key_arn) + self.assertEqual(generator.depends_on, self.depends_on) + self.assertEqual(generator.resource_attributes, self.resource_attributes) + self.assertEqual(generator.passthrough_resource_attributes, self.passthrough_resource_attributes) + + def test_to_cloudformation_with_provided_permissions(self): + """Test to_cloudformation with provided operator role""" + operator_role = "arn:aws:iam::123456789012:role/test" + + generator = CapacityProviderGenerator( + self.logical_id, + capacity_provider_name="test-provider", + vpc_config=self.vpc_config, + operator_role=operator_role, + tags=self.tags, + instance_requirements=self.instance_requirements, + scaling_config=self.scaling_config, + kms_key_arn=self.kms_key_arn, + ) + + resources = generator.to_cloudformation() + + # Should only create the capacity provider resource + self.assertEqual(len(resources), 1) + self.assertIsInstance(resources[0], LambdaCapacityProvider) + + resources = self.extract_resource(resources) + + # Verify capacity provider properties + capacity_provider = resources[self.logical_id] + self.assertIsNotNone(capacity_provider) + + # Use to_dict() to verify properties + properties = capacity_provider["Properties"] + self.assertEqual(properties["CapacityProviderName"], "test-provider") + self.assertEqual( + properties["VpcConfig"], {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + ) + self.assertEqual(properties["PermissionsConfig"]["CapacityProviderOperatorRoleArn"], operator_role) + self.assertEqual(properties["KMSKeyArn"], self.kms_key_arn) + + def test_to_cloudformation_with_auto_generated_permissions(self): + """Test to_cloudformation with auto-generated operator role""" + generator = CapacityProviderGenerator( + self.logical_id, + capacity_provider_name="test-provider", + vpc_config=self.vpc_config, + operator_role=None, + tags=self.tags, + instance_requirements=self.instance_requirements, + scaling_config=self.scaling_config, + kms_key_arn=self.kms_key_arn, + ) + + resources = generator.to_cloudformation() + + # Should create capacity provider and operator role (2 resources) + self.assertEqual(len(resources), 2) + + resources = self.extract_resource(resources) + + capacity_provider = resources[self.logical_id] + operator_role = resources[f"{self.logical_id}OperatorRole"] + + # Verify capacity provider + self.assertEqual(capacity_provider["Type"], "AWS::Lambda::CapacityProvider") + self.assertIn({"Key": "lambda:createdBy", "Value": "SAM"}, capacity_provider["Properties"]["Tags"]) + self.assertIn({"Key": "Environment", "Value": "Production"}, capacity_provider["Properties"]["Tags"]) + capacity_provider_properties = capacity_provider["Properties"] + self.assertEqual( + capacity_provider_properties["PermissionsConfig"]["CapacityProviderOperatorRoleArn"], + fnGetAtt(f"{self.logical_id}OperatorRole", "Arn"), + ) + + # Verify operator role + self.assertEqual(operator_role["Type"], "AWS::IAM::Role") + self.assertIn({"Key": "lambda:createdBy", "Value": "SAM"}, operator_role["Properties"]["Tags"]) + self.assertNotIn({"Key": "Environment", "Value": "Production"}, operator_role["Properties"]["Tags"]) + + def test_transform_instance_requirements(self): + """Test _transform_instance_requirements method""" + generator = CapacityProviderGenerator(self.logical_id, instance_requirements=self.instance_requirements) + + result = generator._transform_instance_requirements() + + self.assertEqual( + result, + {"Architectures": ["arm64"], "AllowedInstanceTypes": ["c5.xlarge"], "ExcludedInstanceTypes": ["t2.micro"]}, + ) + + def test_transform_scaling_config_with_manual_policies(self): + """Test _transform_scaling_config method with manual scaling policies""" + generator = CapacityProviderGenerator(self.logical_id, scaling_config=self.scaling_config) + + result = generator._transform_scaling_config() + + self.assertEqual( + result, + { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + {"PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", "TargetValue": 70.0}, + ], + }, + ) + + def test_transform_scaling_config_without_manual_policies(self): + """Test _transform_scaling_config method without manual scaling policies""" + scaling_config = {"MaxVCpuCount": 10} + generator = CapacityProviderGenerator(self.logical_id, scaling_config=scaling_config) + + result = generator._transform_scaling_config() + + self.assertEqual(result, {"MaxVCpuCount": 10, "ScalingMode": "Auto"}) + + def test_transform_tags(self): + """Test _transform_tags method""" + generator = CapacityProviderGenerator(self.logical_id, tags=self.tags) + + result = generator._transform_tags(self.tags) + + # Should include SAM tag and user-provided tags + self.assertEqual(len(result), 2) + self.assertIn({"Key": "lambda:createdBy", "Value": "SAM"}, result) + self.assertIn({"Key": "Environment", "Value": "Production"}, result) + + def test_create_operator_role(self): + """Test _create_operator_role method""" + generator = CapacityProviderGenerator( + self.logical_id, passthrough_resource_attributes=self.passthrough_resource_attributes + ) + + with patch("samtranslator.model.capacity_provider.generators.ArnGenerator") as mock_arn_generator: + mock_arn_generator.generate_aws_managed_policy_arn.return_value = ( + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ) + + result = generator._create_operator_role() + + self.assertEqual(result.logical_id, f"{self.logical_id}OperatorRole") + + # Use to_dict() to verify properties + role_dict = result.to_dict() + logical_id = f"{self.logical_id}OperatorRole" + properties = role_dict[logical_id]["Properties"] + + # Verify assume role policy document + assume_role_policy = properties["AssumeRolePolicyDocument"] + self.assertEqual(assume_role_policy["Version"], "2012-10-17") + self.assertEqual(len(assume_role_policy["Statement"]), 1) + self.assertEqual(assume_role_policy["Statement"][0]["Principal"]["Service"], ["lambda.amazonaws.com"]) + + # Verify managed policy ARNs + self.assertEqual(len(properties["ManagedPolicyArns"]), 1) + self.assertEqual( + properties["ManagedPolicyArns"][0], + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator", + ) + + # Verify passthrough attributes + self.assertEqual(role_dict[logical_id]["Condition"], "MyCondition") + + def extract_resource(self, resource_array: List[Resource]): + return {r.logical_id: r.to_dict()[r.logical_id] for r in resource_array} diff --git a/tests/model/capacity_provider/test_resources.py b/tests/model/capacity_provider/test_resources.py new file mode 100644 index 0000000000..66afa9d435 --- /dev/null +++ b/tests/model/capacity_provider/test_resources.py @@ -0,0 +1,80 @@ +from unittest import TestCase + +from samtranslator.model.capacity_provider.resources import LambdaCapacityProvider + + +class TestLambdaCapacityProvider(TestCase): + def test_resource_type(self): + """Test that the resource type is set correctly""" + capacity_provider = LambdaCapacityProvider("MyCapacityProvider") + self.assertEqual(capacity_provider.resource_type, "AWS::Lambda::CapacityProvider") + + def test_properties(self): + """Test that properties are set correctly""" + capacity_provider = LambdaCapacityProvider("MyCapacityProvider") + + # Set properties + capacity_provider.CapacityProviderName = "test-provider" + capacity_provider.VpcConfig = {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + capacity_provider.PermissionsConfig = { + "InstanceProfileArn": "arn:aws:iam::123456789012:instance-profile/test", + "CapacityProviderOperatorRoleArn": "arn:aws:iam::123456789012:role/test", + } + capacity_provider.Tags = [ + {"Key": "lambda:createdBy", "Value": "SAM"}, + {"Key": "Environment", "Value": "Production"}, + ] + capacity_provider.InstanceRequirements = {"Architectures": ["arm64"], "AllowedInstanceTypes": ["c5.xlarge"]} + capacity_provider.CapacityProviderScalingConfig = { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + {"PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", "TargetValue": 70.0} + ], + } + capacity_provider.KMSKeyArn = "arn:aws:kms:us-west-2:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456" + + # Verify properties + self.assertEqual(capacity_provider.CapacityProviderName, "test-provider") + self.assertEqual( + capacity_provider.VpcConfig, {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + ) + self.assertEqual( + capacity_provider.PermissionsConfig, + { + "InstanceProfileArn": "arn:aws:iam::123456789012:instance-profile/test", + "CapacityProviderOperatorRoleArn": "arn:aws:iam::123456789012:role/test", + }, + ) + self.assertEqual( + capacity_provider.Tags, + [{"Key": "lambda:createdBy", "Value": "SAM"}, {"Key": "Environment", "Value": "Production"}], + ) + self.assertEqual( + capacity_provider.InstanceRequirements, {"Architectures": ["arm64"], "AllowedInstanceTypes": ["c5.xlarge"]} + ) + self.assertEqual( + capacity_provider.CapacityProviderScalingConfig, + { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + {"PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", "TargetValue": 70.0} + ], + }, + ) + self.assertEqual( + capacity_provider.KMSKeyArn, "arn:aws:kms:us-west-2:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456" + ) + + def test_runtime_attributes(self): + """Test that runtime attributes are generated correctly""" + capacity_provider = LambdaCapacityProvider("MyCapacityProvider") + + # Test name attribute + name_attr = capacity_provider.get_runtime_attr("name") + self.assertEqual(name_attr, {"Ref": "MyCapacityProvider"}) + + # Test arn attribute + arn_attr = capacity_provider.get_runtime_attr("arn") + self.assertEqual(arn_attr, {"Fn::GetAtt": ["MyCapacityProvider", "Arn"]}) diff --git a/tests/model/test_sam_resources.py b/tests/model/test_sam_resources.py index b53649f107..30a7f05ffd 100644 --- a/tests/model/test_sam_resources.py +++ b/tests/model/test_sam_resources.py @@ -11,6 +11,7 @@ from samtranslator.model.packagetype import IMAGE, ZIP from samtranslator.model.sam_resources import ( SamApi, + SamCapacityProvider, SamConnector, SamFunction, SamGraphQLApi, @@ -738,3 +739,61 @@ def test_function_datasource_set_with_none(): api = SamGraphQLApi("MyApi") none_datasource = api._construct_none_datasource("foo") assert none_datasource + + +class TestSamCapacityProvider(TestCase): + """Tests for SamCapacityProvider""" + + def setUp(self): + self.intrinsics_resolver = IntrinsicsResolver({}) + self.kwargs = { + "intrinsics_resolver": self.intrinsics_resolver, + "resource_resolver": ResourceResolver({}), + } + + def test_basic_capacity_provider_without_propagate_tags(self): + """Test that tags are correctly set on the capacity provider""" + capacity_provider = SamCapacityProvider("MyCapacityProvider") + capacity_provider.VpcConfig = {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + capacity_provider.Tags = {"Environment": "Production", "Project": "ServerlessApp"} + + resources = capacity_provider.to_cloudformation(**self.kwargs) + + # Verify the capacity provider has the expected tags + lambda_capacity_providers = [ + r for r in resources if hasattr(r, "resource_type") and r.resource_type == "AWS::Lambda::CapacityProvider" + ] + self.assertEqual(len(lambda_capacity_providers), 1) + + # Check that the tags are present in the capacity provider + tags = lambda_capacity_providers[0].Tags + if not tags: + self.fail("CapacityProvider resource generated with missing tags.") + self.assertEqual(sorted([tag["Key"] for tag in tags]), ["Environment", "Project", "lambda:createdBy"]) + self.assertEqual(sorted([tag["Value"] for tag in tags]), ["Production", "SAM", "ServerlessApp"]) + + # Verify that IAM resources don't have user tags by default + iam_resources = [ + r for r in resources if hasattr(r, "resource_type") and r.resource_type.startswith("AWS::IAM::") + ] + for resource in iam_resources: + if hasattr(resource, "Tags") and resource.Tags: + tags = resource.Tags + self.assertEqual([tag["Key"] for tag in tags], ["lambda:createdBy"]) + self.assertEqual([tag["Value"] for tag in tags], ["SAM"]) + + def test_capacity_provider_with_propagate_tags(self): + """Test that tags are propagated to all resources when PropagateTags is True""" + capacity_provider = SamCapacityProvider("MyCapacityProvider") + capacity_provider.VpcConfig = {"SubnetIds": ["subnet-123", "subnet-456"], "SecurityGroupIds": ["sg-123"]} + capacity_provider.Tags = {"Environment": "Production", "Project": "ServerlessApp"} + capacity_provider.PropagateTags = True + + resources = capacity_provider.to_cloudformation(**self.kwargs) + + # Check that tags are propagated to all resources + for resource in resources: + if hasattr(resource, "Tags") and resource.Tags: + tags = resource.Tags + self.assertEqual(sorted([tag["Key"] for tag in tags]), ["Environment", "Project", "lambda:createdBy"]) + self.assertEqual(sorted([tag["Value"] for tag in tags]), ["Production", "SAM", "ServerlessApp"]) diff --git a/tests/schema/test_validate_schema.py b/tests/schema/test_validate_schema.py index 2c1a716ed7..a6b3b7d044 100644 --- a/tests/schema/test_validate_schema.py +++ b/tests/schema/test_validate_schema.py @@ -58,6 +58,7 @@ # TODO: Support globals (e.g. somehow make all fields of a model optional only for Globals) "api_with_custom_base_path", "function_with_tracing", # TODO: intentionally skip this tests to cover incorrect scenarios + "capacity_provider_global_with_functions", # Skip for Global case since customers can define partial field for global ] diff --git a/tests/test_model.py b/tests/test_model.py index 4e003172be..9b78fed9f0 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1,11 +1,13 @@ -from typing import Any, List +from typing import Any, List, Optional from unittest import TestCase from unittest.mock import Mock import pytest +from samtranslator.internal.schema_source.common import BaseModel from samtranslator.intrinsics.resource_refs import SupportedResourceReferences -from samtranslator.model import PropertyType, Resource, ResourceTypeResolver, SamResourceMacro +from samtranslator.model import PropertyType, Resource, ResourceTypeResolver, SamResourceMacro, ValidationRule from samtranslator.model.exceptions import InvalidResourceException +from samtranslator.model.types import IS_BOOL, IS_DICT, IS_INT, IS_STR from samtranslator.plugins import LifeCycleEvents @@ -171,10 +173,13 @@ def test_resource_must_override_runtime_attributes(self): class NewResource(Resource): resource_type = "foo" property_types = {} - runtime_attrs = {"attr1": Mock(), "attr2": Mock()} - runtime_attrs["attr1"].return_value = "value1" - runtime_attrs["attr2"].return_value = "value2" + mock_attr1 = Mock() + mock_attr2 = Mock() + mock_attr1.return_value = "value1" + mock_attr2.return_value = "value2" + + runtime_attrs = {"attr1": mock_attr1, "attr2": mock_attr2} logical_id = "SomeId" resource = NewResource(logical_id) @@ -336,12 +341,12 @@ class TestResourceTypeResolver(TestCase): def test_can_resolve_must_handle_null_resource_dict(self): resolver = ResourceTypeResolver() - self.assertFalse(resolver.can_resolve(None)) + self.assertFalse(resolver.can_resolve(None)) # type: ignore[arg-type] def test_can_resolve_must_handle_non_dict(self): resolver = ResourceTypeResolver() - self.assertFalse(resolver.can_resolve("some string value")) + self.assertFalse(resolver.can_resolve("some string value")) # type: ignore[arg-type] def test_can_resolve_must_handle_dict_without_type(self): resolver = ResourceTypeResolver() @@ -391,3 +396,393 @@ class MyResource(Resource): mock_sam_plugins.act.assert_called_once_with( LifeCycleEvents.before_transform_resource, "logicalId", resource_type, expected_properties ) + + +class TestSamResourceMacro(TestCase): + """ + Test validation functionality in SamResourceMacro + + IMPORTANT: These tests document the CURRENT BEHAVIOR of the validation system, + which has known bugs. The validation logic incorrectly treats property conditions + that evaluate to False as "present" for validation purposes. + + Known Issues: + 1. Property conditions like "Type=CUSTOM" that evaluate to False are still + considered "present" because False != None + 2. Boolean comparisons fail because True != "True" (string comparison) + 3. Integer comparisons fail because 42 != "42" (string comparison) + 4. Validation rules trigger even when their conditions don't match + """ + + def setUp(self): + """Set up common test fixtures""" + self.ValidationRule = ValidationRule + + # Test setting properties using BaseModel from samtranslator.internal.schema_source.common + class TestSettingProperties(BaseModel): + NestedVar1: Optional[str] = None + NestedVar2: Optional[str] = None + + # Comprehensive schema class for testing using BaseModel from samtranslator.internal.schema_source.common + class TestProperties(BaseModel): + ConditionalVar1: Optional[int] = None + ConditionalVar2: Optional[int] = None + ConditionalVar3: Optional[int] = None + ExclusiveVar1: Optional[str] = None + ExclusiveVar2: Optional[str] = None + ExclusiveVar3: Optional[str] = None + InclusiveVar1: Optional[bool] = None + InclusiveVar2: Optional[bool] = None + InclusiveVar3: Optional[bool] = None + NestedSetting1: Optional[TestSettingProperties] = None + NestedSetting2: Optional[TestSettingProperties] = None + NestedSetting3: Optional[TestSettingProperties] = None + + self.TestProperties = TestProperties + self.TestSettingProperties = TestSettingProperties + + # Reusable test resource class extending SamResourceMacro + class TestResource(SamResourceMacro): + resource_type = "Test::Resource" + property_types = { + "ConditionalVar1": PropertyType(False, IS_INT), + "ConditionalVar2": PropertyType(False, IS_INT), + "ConditionalVar3": PropertyType(False, IS_INT), + "ExclusiveVar1": PropertyType(False, IS_STR), + "ExclusiveVar2": PropertyType(False, IS_STR), + "ExclusiveVar3": PropertyType(False, IS_STR), + "InclusiveVar1": PropertyType(False, IS_BOOL), + "InclusiveVar2": PropertyType(False, IS_BOOL), + "InclusiveVar3": PropertyType(False, IS_BOOL), + "NestedSetting1": PropertyType(False, IS_DICT), + "NestedSetting2": PropertyType(False, IS_DICT), + "NestedSetting3": PropertyType(False, IS_DICT), + } + + def to_cloudformation(self, **kwargs): + return [] + + self.TestResource = TestResource + + class TestValidateBeforeTransform(TestCase): + """Test cases for validate_before_transform() method""" + + def setUp(self): + """Set up test fixtures for validate_before_transform tests""" + # Import from parent class + parent = TestSamResourceMacro() + parent.setUp() + self.ValidationRule = parent.ValidationRule + self.TestProperties = parent.TestProperties + self.TestSettingProperties = parent.TestSettingProperties + self.TestResource = parent.TestResource + + def test_validate_before_transform_all_rules_pass(self): + """Test successful validation when all rules are satisfied""" + + class Resource(self.TestResource): + __validation_rules__ = [ + (self.ValidationRule.CONDITIONAL_REQUIREMENT, ["ConditionalVar1", "ConditionalVar2"]), + (self.ValidationRule.CONDITIONAL_REQUIREMENT, ["ConditionalVar2", "ConditionalVar3"]), + ( + self.ValidationRule.CONDITIONAL_REQUIREMENT, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar2"], + ), + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["ExclusiveVar1", "ExclusiveVar2"]), + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["ExclusiveVar2", "ExclusiveVar3"]), + ( + self.ValidationRule.MUTUALLY_EXCLUSIVE, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar1"], + ), + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["NestedSetting1.NestedVar2", "ExclusiveVar3"]), + (self.ValidationRule.MUTUALLY_INCLUSIVE, ["InclusiveVar1", "ExclusiveVar1"]), + ( + self.ValidationRule.MUTUALLY_INCLUSIVE, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar2"], + ), + ( + self.ValidationRule.MUTUALLY_INCLUSIVE, + ["NestedSetting2.NestedVar2", "NestedSetting3.NestedVar2"], + ), + ] + + resource = Resource("TestId") + + # Happy case: All rules satisfied + resource.ConditionalVar1 = 1 + resource.ConditionalVar2 = 2 + resource.ConditionalVar3 = 3 + resource.ExclusiveVar1 = "ONLY_EXCLUSIVE_VAL" # cannot have ExclusiveVar2, ExclusiveVar3 + resource.InclusiveVar1 = True + resource.InclusiveVar2 = False + resource.NestedSetting2 = {"NestedVar2": "NestedVar2"} + resource.NestedSetting1 = {"NestedVar1": "NestedVar1"} + resource.NestedSetting3 = {"NestedVar2": "NestedVar2"} + + # Should not raise any exception + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + + def test_conditional_requirement_rule(self): + """Test CONDITIONAL_REQUIREMENT validation rule""" + + class Resource(self.TestResource): + __validation_rules__ = [ + (self.ValidationRule.CONDITIONAL_REQUIREMENT, ["ConditionalVar1", "ConditionalVar2"]), + (self.ValidationRule.CONDITIONAL_REQUIREMENT, ["ConditionalVar1", "ConditionalVar3"]), + ( + self.ValidationRule.CONDITIONAL_REQUIREMENT, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar2"], + ), + ] + + resource = Resource("TestId") + + # Test 1: Should show 3 errors + resource.ConditionalVar1 = 1 + resource.NestedSetting1 = {"NestedVar1": "NestedVar1"} + with self.assertRaises(InvalidResourceException) as error_1: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + self.assertEqual( + "Resource with id [TestId] is invalid. 'ConditionalVar1' requires 'ConditionalVar2'.\n'ConditionalVar1' requires 'ConditionalVar3'.\n'NestedSetting1.NestedVar1' requires 'NestedSetting2.NestedVar2'.", + error_1.exception.message, + ) + + # Test 2: should show 2 error + resource.ConditionalVar2 = 2 + with self.assertRaises(InvalidResourceException) as error_2: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + self.assertEqual( + "Resource with id [TestId] is invalid. 'ConditionalVar1' requires 'ConditionalVar3'.\n'NestedSetting1.NestedVar1' requires 'NestedSetting2.NestedVar2'.", + error_2.exception.message, + ) + + # Test 3: should show 1 error + resource.ConditionalVar3 = 3 + with self.assertRaises(InvalidResourceException) as error_3: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + self.assertEqual( + "Resource with id [TestId] is invalid. 'NestedSetting1.NestedVar1' requires 'NestedSetting2.NestedVar2'.", + error_3.exception.message, + ) + + def test_mutually_inclusive_rule(self): + """Test MUTUALLY_INCLUSIVE validation rule""" + + class Resource(self.TestResource): + __validation_rules__ = [ + # When InclusiveVar1 is specified, InclusiveVar2 and InclusiveVar3 should be present + (self.ValidationRule.MUTUALLY_INCLUSIVE, ["InclusiveVar1", "InclusiveVar2"]), + (self.ValidationRule.MUTUALLY_INCLUSIVE, ["InclusiveVar1", "InclusiveVar3"]), + # When NestedSetting1.NestedVar1 is specified, NestedSetting2.NestedVar2 should be present + ( + self.ValidationRule.MUTUALLY_INCLUSIVE, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar2"], + ), + ] + + resource = Resource("TestId") + + # Test 1: When InclusiveVar1 is present, both InclusiveVar2 and InclusiveVar3 must also be present + resource.InclusiveVar1 = True + with self.assertRaises(InvalidResourceException) as error_1: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + expected_errors = [ + "Properties must be used together: InclusiveVar1 and InclusiveVar2.", + "Properties must be used together: InclusiveVar1 and InclusiveVar3.", + ] + for expected_error in expected_errors: + self.assertIn(expected_error, error_1.exception.message) + + # Test 2: When InclusiveVar2 is provided, only one error should remain + resource.InclusiveVar2 = True + with self.assertRaises(InvalidResourceException) as error_2: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + self.assertIn( + "Properties must be used together: InclusiveVar1 and InclusiveVar3.", error_2.exception.message + ) + + # Test 3: When all inclusive vars are provided, no error for inclusive vars + resource.InclusiveVar3 = True + # Should not raise exception for inclusive vars + resource.validate_before_transform(self.TestProperties) + + # Test 4: When NestedSetting1.NestedVar1 is specified, NestedSetting2.NestedVar2 should be present + resource.NestedSetting1 = {"NestedVar1": "AUTO"} + with self.assertRaises(InvalidResourceException) as error_4: + resource.validate_before_transform(self.TestProperties) + self.assertEqual( + "Resource with id [TestId] is invalid. Properties must be used together: NestedSetting1.NestedVar1 and NestedSetting2.NestedVar2.", + error_4.exception.message, + ) + + # Test 5: When both nested properties are provided, no error + resource.NestedSetting2 = {"NestedVar2": "REQUIRED"} + # Should not raise exception + resource.validate_before_transform(self.TestProperties) + + def test_mutually_exclusive_rule(self): + """Test MUTUALLY_EXCLUSIVE validation rule""" + + class Resource(self.TestResource): + __validation_rules__ = [ + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["ExclusiveVar1", "ExclusiveVar2"]), + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["ExclusiveVar2", "ExclusiveVar3"]), + ( + self.ValidationRule.MUTUALLY_EXCLUSIVE, + ["NestedSetting1.NestedVar1", "NestedSetting2.NestedVar1"], + ), + (self.ValidationRule.MUTUALLY_EXCLUSIVE, ["NestedSetting1.NestedVar2", "ExclusiveVar3"]), + ] + + resource = Resource("TestId") + + # Test 1: Cannot have both ExclusiveVar1 and ExclusiveVar2 + resource.ExclusiveVar1 = "value1" + resource.ExclusiveVar2 = "value2" + with self.assertRaises(InvalidResourceException) as error_1: + resource.validate_before_transform(self.TestProperties) + self.assertEqual( + "Resource with id [TestId] is invalid. Cannot specify 'ExclusiveVar1' and 'ExclusiveVar2' together.", + error_1.exception.message, + ) + + # Test 2: Can have ExclusiveVar1 alone + resource.ExclusiveVar2 = None # Remove ExclusiveVar2 + # Should not raise exception + resource.validate_before_transform(self.TestProperties) + + # Test 3: Cannot have both ExclusiveVar2 and ExclusiveVar3 + resource.ExclusiveVar1 = None # Remove ExclusiveVar1 + resource.ExclusiveVar2 = "value2" + resource.ExclusiveVar3 = "value3" + with self.assertRaises(InvalidResourceException) as error_3: + resource.validate_before_transform(self.TestProperties) + self.assertEqual( + "Resource with id [TestId] is invalid. Cannot specify 'ExclusiveVar2' and 'ExclusiveVar3' together.", + error_3.exception.message, + ) + + # Test 4: Multiple exclusive violations - should show all errors + resource.ExclusiveVar1 = "value1" # This conflicts with ExclusiveVar2 + resource.ExclusiveVar2 = "value2" # This conflicts with both ExclusiveVar1 and ExclusiveVar3 + resource.ExclusiveVar3 = "value3" # This conflicts with ExclusiveVar2 + with self.assertRaises(InvalidResourceException) as error_4: + resource.validate_before_transform(self.TestProperties, collect_all_errors=True) + expected_errors = [ + "Cannot specify 'ExclusiveVar1' and 'ExclusiveVar2' together.", + "Cannot specify 'ExclusiveVar2' and 'ExclusiveVar3' together.", + ] + for expected_error in expected_errors: + self.assertIn(expected_error, error_4.exception.message) + + # Test 5: Cannot have both NestedSetting1.NestedVar1 and NestedSetting2.NestedVar1 + resource.ExclusiveVar1 = None # Clear previous conflicts + resource.ExclusiveVar2 = None + resource.ExclusiveVar3 = None + resource.NestedSetting1 = {"NestedVar1": "nested_value1"} + resource.NestedSetting2 = {"NestedVar1": "nested_value2"} + with self.assertRaises(InvalidResourceException) as error_5: + resource.validate_before_transform(self.TestProperties) + self.assertEqual( + "Resource with id [TestId] is invalid. Cannot specify 'NestedSetting1.NestedVar1' and 'NestedSetting2.NestedVar1' together.", + error_5.exception.message, + ) + + # Test 6: Cannot have both NestedSetting1.NestedVar2 and ExclusiveVar3 + resource.NestedSetting2 = None # Remove previous conflict + resource.NestedSetting1 = {"NestedVar2": "nested_value2"} + resource.ExclusiveVar3 = "value3" + with self.assertRaises(InvalidResourceException) as error_6: + resource.validate_before_transform(self.TestProperties) + self.assertEqual( + "Resource with id [TestId] is invalid. Cannot specify 'NestedSetting1.NestedVar2' and 'ExclusiveVar3' together.", + error_6.exception.message, + ) + + # Test 7: Can have nested properties that don't conflict + resource.ExclusiveVar3 = None # Remove conflict + resource.NestedSetting1 = {"NestedVar1": "nested_value1"} # This doesn't conflict with NestedVar2 + resource.NestedSetting2 = {"NestedVar2": "nested_value2"} # This doesn't conflict with NestedVar1 + # Should not raise exception + resource.validate_before_transform(self.TestProperties) + + class TestFormatAllErrors(TestCase): + """Test cases for _format_all_errors() method""" + + def setUp(self): + """Set up test fixtures for _format_all_errors tests""" + # Import from parent class + parent = TestSamResourceMacro() + parent.setUp() + self.ValidationRule = parent.ValidationRule + self.TestProperties = parent.TestProperties + self.TestSettingProperties = parent.TestSettingProperties + self.TestResource = parent.TestResource + + @pytest.mark.parametrize( + "mock_errors,expected_count,expected_messages", + [ + # Single type error + ( + [{"loc": ("ConditionalVar1",), "msg": "not a valid int", "type": "type_error.integer"}], + 1, + ["Property 'ConditionalVar1' value must be integer."], + ), + # Union type consolidation + ( + [ + {"loc": ("ExclusiveVar1",), "msg": "not a valid str", "type": "type_error.str"}, + {"loc": ("ExclusiveVar1",), "msg": "not a valid int", "type": "type_error.integer"}, + ], + 1, + ["Property 'ExclusiveVar1' value must be string or integer."], + ), + # Missing property error + ( + [{"loc": ("RequiredProperty",), "msg": "field required", "type": "value_error.missing"}], + 1, + ["Property 'RequiredProperty' is required."], + ), + # Invalid property error + ( + [{"loc": ("InvalidProperty",), "msg": "extra fields not permitted", "type": "value_error.extra"}], + 1, + ["Property 'InvalidProperty' is an invalid property."], + ), + # Nested property error + ( + [{"loc": ("NestedSetting1", "NestedVar1"), "msg": "not a valid str", "type": "type_error.str"}], + 1, + ["Property 'NestedSetting1.NestedVar1' value must be string."], + ), + # Multiple properties with errors + ( + [ + {"loc": ("ConditionalVar1",), "msg": "not a valid int", "type": "type_error.integer"}, + {"loc": ("ExclusiveVar1",), "msg": "field required", "type": "value_error.missing"}, + {"loc": ("NestedSetting1", "NestedVar1"), "msg": "not a valid str", "type": "type_error.str"}, + ], + 3, + [ + "Property 'ConditionalVar1' value must be integer.", + "Property 'ExclusiveVar1' is required.", + "Property 'NestedSetting1.NestedVar1' value must be string.", + ], + ), + # Fallback error formatting + ( + [{"loc": ("SomeProperty",), "msg": "Some Custom Error Message", "type": "custom_error"}], + 1, + ["Property 'SomeProperty' some custom error message."], + ), + ], + ) + def test_format_all_errors(self, mock_errors, expected_count, expected_messages): + """Test formatting various types of validation errors""" + resource = self.TestResource("TestId") + + formatted_errors = resource._format_all_errors(mock_errors) + self.assertEqual(len(formatted_errors), expected_count) + + for expected_message in expected_messages: + self.assertIn(expected_message, formatted_errors) diff --git a/tests/translator/input/capacity_provider_custom_permissions.yaml b/tests/translator/input/capacity_provider_custom_permissions.yaml new file mode 100644 index 0000000000..f2b8a70080 --- /dev/null +++ b/tests/translator/input/capacity_provider_custom_permissions.yaml @@ -0,0 +1,74 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: CapacityProvider with custom permissions configuration test + +Resources: + # Create custom roles that match what SAM would generate + CustomPermissionsCapacityProviderOperatorRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: CapacityProviderOperatorRolePolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:TerminateInstances + - ec2:RunInstances + - ec2:DescribeInstanceStatus + - ec2:DescribeInstances + - ec2:CreateTags + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:instance/* + - !Sub arn:${AWS::Partition}:ec2:*:*:network-interface/* + - !Sub arn:${AWS::Partition}:ec2:*:*:volume/* + Condition: + StringEquals: + ec2:ManagedResourceOperator: scaler.lambda.amazonaws.com + - Effect: Allow + Action: + - ec2:DescribeAvailabilityZones + - ec2:DescribeCapacityReservations + - ec2:DescribeInstanceTypeOfferings + - ec2:DescribeInstanceTypes + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + Resource: '*' + - Effect: Allow + Action: + - ec2:RunInstances + - ec2:CreateNetworkInterface + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:subnet/* + - !Sub arn:${AWS::Partition}:ec2:*:*:security-group/* + - Effect: Allow + Action: + - ec2:RunInstances + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:image/* + Condition: + Bool: + ec2:Public: 'true' + Tags: + - Key: lambda:createdBy + Value: SAM + + # Reference the custom roles in the capacity provider + CustomPermissionsCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: custom-permissions-provider + VpcConfig: + SecurityGroupIds: + - sg-12345678 + SubnetIds: + - subnet-12345678 + OperatorRole: !GetAtt CustomPermissionsCapacityProviderOperatorRole.Arn diff --git a/tests/translator/input/capacity_provider_full.yaml b/tests/translator/input/capacity_provider_full.yaml new file mode 100644 index 0000000000..bf8b462887 --- /dev/null +++ b/tests/translator/input/capacity_provider_full.yaml @@ -0,0 +1,28 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Full CapacityProvider configuration test + +Resources: + FullCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: customized-capacity-provider + VpcConfig: + SecurityGroupIds: + - sg-12345678 + - sg-87654321 + SubnetIds: + - subnet-12345678 + Tags: + Environment: Production + Team: Tooling + InstanceRequirements: + Architectures: + - arm64 + AllowedTypes: + - c5.xlarge + - c5.2xlarge + ScalingConfig: + MaxVCpuCount: 10 + AverageCPUUtilization: 75.0 + KMSKeyArn: arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv diff --git a/tests/translator/input/capacity_provider_global_with_functions.yaml b/tests/translator/input/capacity_provider_global_with_functions.yaml new file mode 100644 index 0000000000..1e675cfe7f --- /dev/null +++ b/tests/translator/input/capacity_provider_global_with_functions.yaml @@ -0,0 +1,188 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: CapacityProvider with Globals and intrinsic functions test + +Parameters: + Environment: + Type: String + Default: dev + AllowedValues: [dev, staging, prod] + Team: + Type: String + Default: serverless-team + + MemoryGiBPerVCpu: + Type: Number + Default: 2.5 + + MaxConcurrency: + Type: Number + Default: 100 + + SecurityGroupId: + Type: String + Default: sg-12345678 + + SubnetId: + Type: String + Default: subnet-12345678 + +Conditions: + IsProd: !Equals [!Ref Environment, prod] + +Globals: + CapacityProvider: + VpcConfig: + SecurityGroupIds: + - !Ref SecurityGroupId + SubnetIds: + - !Ref SubnetId + ScalingConfig: + AverageCPUUtilization: !If [IsProd, 80.0, 70.0] + Tags: + Environment: !Ref Environment + Team: !Ref Team + ManagedBy: SAM + OperatorRole: !GetAtt CustomPermissionsCapacityProviderOperatorRole.Arn + PropagateTags: true + InstanceRequirements: + Architectures: + - x86_64 + KMSKeyArn: some-kms-arn + + Function: + Runtime: python3.12 + Handler: index.handler + MemorySize: 512 + Timeout: 30 + CapacityProviderConfig: + Arn: !GetAtt GlobalCapacityProvider.Arn + ExecutionEnvironmentMemoryGiBPerVCpu: !Ref MemoryGiBPerVCpu + PerExecutionEnvironmentMaxConcurrency: !Ref MaxConcurrency + FunctionScalingConfig: + MinExecutionEnvironments: !If [IsProd, 2, 1] + MaxExecutionEnvironments: !If [IsProd, 50, 10] + Tags: + Environment: !Ref Environment + Team: !Ref Team + ManagedBy: SAM + Environment: + Variables: + ENV: !Ref Environment + TEAM: !Ref Team + +Resources: + CustomPermissionsCapacityProviderOperatorRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: CapacityProviderOperatorRolePolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:TerminateInstances + - ec2:RunInstances + - ec2:DescribeInstanceStatus + - ec2:DescribeInstances + - ec2:CreateTags + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:instance/* + - !Sub arn:${AWS::Partition}:ec2:*:*:network-interface/* + - !Sub arn:${AWS::Partition}:ec2:*:*:volume/* + Condition: + StringEquals: + ec2:ManagedResourceOperator: scaler.lambda.amazonaws.com + - Effect: Allow + Action: + - ec2:DescribeAvailabilityZones + - ec2:DescribeCapacityReservations + - ec2:DescribeInstanceTypeOfferings + - ec2:DescribeInstanceTypes + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + Resource: '*' + - Effect: Allow + Action: + - ec2:RunInstances + - ec2:CreateNetworkInterface + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:subnet/* + - !Sub arn:${AWS::Partition}:ec2:*:*:security-group/* + - Effect: Allow + Action: + - ec2:RunInstances + Resource: + - !Sub arn:${AWS::Partition}:ec2:*:*:image/* + Condition: + Bool: + ec2:Public: 'true' + # Global Capacity Provider with reduced properties since globals handle common ones + GlobalCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: !Sub "${AWS::StackName}-${Environment}-capacity-provider" + InstanceRequirements: + Architectures: + - arm64 + ExcludedTypes: + - t2.micro + - t2.small + ScalingConfig: + MaxVCpuCount: !If [IsProd, 20, 10] # Support addition + + # Function that uses the capacity provider with intrinsic references + GlobalFunction1: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub "${AWS::StackName}-${Environment}-function-1" + CodeUri: s3://sam-demo-bucket/hello.zip + Description: !Sub "Function 1 in ${Environment} environment managed by ${Team}" + + # Second function with different configuration + GlobalFunction2: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join ['-', [!Ref AWS::StackName, !Ref Environment, function, + '2']] + CodeUri: s3://sam-demo-bucket/hello.zip + Description: !Sub + - Function 2 in ${env} for ${team} team with provider ${provider} + - env: !Ref Environment + team: !Ref Team + provider: !Ref GlobalCapacityProvider + CapacityProviderConfig: + ExecutionEnvironmentMemoryGiBPerVCpu: 4 # support partial override + FunctionScalingConfig: + MinExecutionEnvironments: 3 # support partial override + AutoPublishAlias: Development + +Outputs: + CapacityProviderArn: + Description: ARN of the created capacity provider + Value: !GetAtt GlobalCapacityProvider.Arn + Export: + Name: !Sub "${AWS::StackName}-CapacityProviderArn" + Function1Name: + Description: Name of Function 1 + Value: !Ref GlobalFunction1 + Export: + Name: !Sub "${AWS::StackName}-Function1Name" + Function2Name: + Description: Name of Function 2 + Value: !Ref GlobalFunction2 + Export: + Name: !Sub "${AWS::StackName}-Function2Name" + EnvironmentInfo: + Description: Environment and team information + Value: !Sub "${Environment}-${Team}" + Export: + Name: !Sub "${AWS::StackName}-EnvironmentInfo" diff --git a/tests/translator/input/capacity_provider_minimal.yaml b/tests/translator/input/capacity_provider_minimal.yaml new file mode 100644 index 0000000000..0355d27de1 --- /dev/null +++ b/tests/translator/input/capacity_provider_minimal.yaml @@ -0,0 +1,11 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Minimal CapacityProvider configuration test + +Resources: + MinimalCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + VpcConfig: + SubnetIds: + - subnet-12345678 diff --git a/tests/translator/input/capacity_provider_with_intrinsics.yaml b/tests/translator/input/capacity_provider_with_intrinsics.yaml new file mode 100644 index 0000000000..1fffa1ab23 --- /dev/null +++ b/tests/translator/input/capacity_provider_with_intrinsics.yaml @@ -0,0 +1,68 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: CapacityProvider with intrinsic functions test + +Parameters: + CapacityProviderName: + Type: String + Default: intrinsic-capacity-provider + + SecurityGroupId: + Type: String + Default: sg-12345678 + + SubnetId: + Type: String + Default: subnet-12345678 + + Architecture: + Type: String + Default: arm64 + + AllowedInstanceType: + Type: String + Default: c5.xlarge + + ExcludedInstanceType: + Type: String + Default: t2.micro + + MaxVCpuCount: + Type: Number + Default: 10 + + TargetCPU: + Type: Number + Default: 75.0 + + TargetMemory: + Type: Number + Default: 81.2 + + KMSKeyArn: + Type: String + Default: arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv + +Resources: + IntrinsicCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: !Ref CapacityProviderName + VpcConfig: + SecurityGroupIds: + - !Ref SecurityGroupId + SubnetIds: + - !Ref SubnetId + Tags: + Environment: !Sub "${AWS::StackName}-environment" + Team: !Sub "${AWS::StackName}-team" + InstanceRequirements: + Architectures: + - !Ref Architecture + AllowedTypes: + - !Ref AllowedInstanceType + - !Join [., [c5, 2xlarge]] + ScalingConfig: + MaxVCpuCount: !Ref MaxVCpuCount + AverageCPUUtilization: !Ref TargetCPU + KMSKeyArn: !Ref KMSKeyArn diff --git a/tests/translator/input/capacity_provider_with_mulitple_functions.yaml b/tests/translator/input/capacity_provider_with_mulitple_functions.yaml new file mode 100644 index 0000000000..ae62889bc9 --- /dev/null +++ b/tests/translator/input/capacity_provider_with_mulitple_functions.yaml @@ -0,0 +1,79 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Complete template with capacity provider and functions + +Parameters: + MemoryGiBPerVCpu: + Type: Number + Default: 2.5 + Description: Memory GiB per vCPU for capacity provider +Resources: + # Define a capacity provider resource + MyCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: test-capacity-provider + VpcConfig: + SecurityGroupIds: + - sg-12345678 + SubnetIds: + - subnet-12345678 + InstanceRequirements: + Architectures: + - arm64 + AllowedTypes: + - c5.xlarge + - c5.2xlarge + ScalingConfig: + MaxVCpuCount: 10 + AverageCPUUtilization: 75 + + # Function 1: Basic function with capacity provider reference + BasicLMIFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + CapacityProviderConfig: + Arn: !GetAtt MyCapacityProvider.Arn + ExecutionEnvironmentMemoryGiBPerVCpu: !Ref MemoryGiBPerVCpu + + # Function 2: Function with capacity provider and auto publish alias + LMIFunctionWithAlias: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + Description: Lambda function with capacity provider and auto publish alias + AutoPublishAlias: Production + CapacityProviderConfig: + Arn: !GetAtt MyCapacityProvider.Arn + PerExecutionEnvironmentMaxConcurrency: 50 + ExecutionEnvironmentMemoryGiBPerVCpu: 4 + FunctionScalingConfig: + MinExecutionEnvironments: 2 + MaxExecutionEnvironments: 20 + DeploymentPreference: + Type: Linear10PercentEvery1Minute + + # Function 2: Function with capacity provider and auto publish alias + LMIFunctionWithAliasDeletePolicy: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + Description: Lambda function with capacity provider and auto publish alias + AutoPublishAlias: Production + CapacityProviderConfig: + Arn: !GetAtt MyCapacityProvider.Arn + PerExecutionEnvironmentMaxConcurrency: 50 + ExecutionEnvironmentMemoryGiBPerVCpu: 4 + FunctionScalingConfig: + MinExecutionEnvironments: 2 + MaxExecutionEnvironments: 20 + DeploymentPreference: + Type: Linear10PercentEvery1Minute + VersionDeletionPolicy: Retain diff --git a/tests/translator/input/error_auto_publish_alias_version_deletion_policy.yaml b/tests/translator/input/error_auto_publish_alias_version_deletion_policy.yaml new file mode 100644 index 0000000000..42d9fe3184 --- /dev/null +++ b/tests/translator/input/error_auto_publish_alias_version_deletion_policy.yaml @@ -0,0 +1,11 @@ +Resources: + MinimalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + AutoPublishAlias: '' + DeploymentPreference: + Type: AllAtOnce + VersionDeletionPolicy: true diff --git a/tests/translator/input/error_capacity_provider_missing_subnet_ids.yaml b/tests/translator/input/error_capacity_provider_missing_subnet_ids.yaml new file mode 100644 index 0000000000..14b1cc0a5d --- /dev/null +++ b/tests/translator/input/error_capacity_provider_missing_subnet_ids.yaml @@ -0,0 +1,12 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test missing SubnetIds in VpcConfig for CapacityProvider + +Resources: + CapacityProviderMissingSubnetIds: + Type: AWS::Serverless::CapacityProvider + Properties: + VpcConfig: + SecurityGroupIds: + - sg-12345678 + - sg-87654321 diff --git a/tests/translator/input/error_capacity_provider_missing_vpc_config.yaml b/tests/translator/input/error_capacity_provider_missing_vpc_config.yaml new file mode 100644 index 0000000000..d11496a0c6 --- /dev/null +++ b/tests/translator/input/error_capacity_provider_missing_vpc_config.yaml @@ -0,0 +1,11 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test missing VpcConfig for CapacityProvider + +Resources: + CapacityProviderMissingVpcConfig: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: test-capacity-provider + Tags: + Environment: Test diff --git a/tests/translator/input/error_capacity_provider_multiple_resources_validation.yaml b/tests/translator/input/error_capacity_provider_multiple_resources_validation.yaml new file mode 100644 index 0000000000..d6cb1c3063 --- /dev/null +++ b/tests/translator/input/error_capacity_provider_multiple_resources_validation.yaml @@ -0,0 +1,41 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 + +Resources: + # Resource 1: Missing VpcConfig entirely + CapacityProvider1: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: TestCapacityProvider1 + # VpcConfig is missing (required property) + # Resource 2: Missing SubnetIds in VpcConfig + CapacityProvider2: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: TestCapacityProvider2 + VpcConfig: + # SubnetIds is missing (required nested property) + SecurityGroupIds: + - sg-12345678 + + # Resource 3: Wrong types for nested properties + CapacityProvider3: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: TestCapacityProvider3 + VpcConfig: + SubnetIds: subnet-12345678 # Should be a list, not string + SecurityGroupIds: sg-12345678 # Should be a list, not string + ScalingConfig: + MaxVCpuCount: invalid # Should be a number, not string + # Resource 4: Invalid nested structure + CapacityProvider4: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: TestCapacityProvider4 + VpcConfig: + SubnetIds: + - subnet-12345678 + InvalidProperty: should not be here # Unknown property in VpcConfig + ScalingConfig: + AverageCPUUtilization: not_a_number # Should be a number diff --git a/tests/translator/input/error_capacity_provider_mutually_exclusive_instance_types.yaml b/tests/translator/input/error_capacity_provider_mutually_exclusive_instance_types.yaml new file mode 100644 index 0000000000..7844934d4b --- /dev/null +++ b/tests/translator/input/error_capacity_provider_mutually_exclusive_instance_types.yaml @@ -0,0 +1,24 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test validation rules for capacity provider with mutually exclusive AllowedTypes + and ExcludedTypes + +Resources: + # This capacity provider has both AllowedTypes and ExcludedTypes + # which are mutually exclusive, so it should fail validation + CapacityProviderWithValidationError: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: TestCapacityProvider + VpcConfig: + SubnetIds: + - subnet-12345678 + SecurityGroupIds: + - sg-12345678 + InstanceRequirements: + AllowedTypes: + - c5.xlarge + - c5.2xlarge + ExcludedTypes: + - t2.micro + - t2.small diff --git a/tests/translator/input/error_capacity_provider_typo_properties.yaml b/tests/translator/input/error_capacity_provider_typo_properties.yaml new file mode 100644 index 0000000000..16f44c25ca --- /dev/null +++ b/tests/translator/input/error_capacity_provider_typo_properties.yaml @@ -0,0 +1,18 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test typos in property names for CapacityProvider + +Resources: + CapacityProviderTypoProperties: + Type: AWS::Serverless::CapacityProvider + Properties: + VpcConfig: + SubnetIds: + - subnet-12345678 + CapacityProviderNam: test-capacity-provider # Typo: missing 'e' + VPCConfig: # Typo: should be VpcConfig + SubnetIds: + - subnet-87654321 + ScalingConfg: # Typo: missing 'i' + MaxVCpuCount: 10 + KMSKeyArn: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 # Typo: should be KMSKeyArn diff --git a/tests/translator/input/error_capacity_provider_unknown_properties.yaml b/tests/translator/input/error_capacity_provider_unknown_properties.yaml new file mode 100644 index 0000000000..c8a0a79ac3 --- /dev/null +++ b/tests/translator/input/error_capacity_provider_unknown_properties.yaml @@ -0,0 +1,19 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test unknown properties for CapacityProvider + +Resources: + CapacityProviderUnknownProperties: + Type: AWS::Serverless::CapacityProvider + Properties: + VpcConfig: + SubnetIds: + - subnet-12345678 + UnknownVpcProperty: invalid # Unknown property in VpcConfig + UnknownProperty: some-value # Unknown property + InvalidConfig: # Unknown nested property + SomeNestedValue: test + ScalingConfig: + MaxVCpuCount: 10 + InvalidScalingProperty: test # Unknown property in ScalingConfig + OperatorRole: dfasd diff --git a/tests/translator/input/error_capacity_provider_wrong_types.yaml b/tests/translator/input/error_capacity_provider_wrong_types.yaml new file mode 100644 index 0000000000..41d41dc2d3 --- /dev/null +++ b/tests/translator/input/error_capacity_provider_wrong_types.yaml @@ -0,0 +1,15 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test wrong data types for CapacityProvider properties + +Resources: + CapacityProviderWrongTypes: + Type: AWS::Serverless::CapacityProvider + Properties: + VpcConfig: + SubnetIds: subnet-12345678 # Should be a list, not string + SecurityGroupIds: sg-12345678 # Should be a list, not string + Tags: invalid-tags # Should be a dict, not string + ScalingConfig: + MaxVCpuCount: not-a-number # Should be integer, not string + AverageCPUUtilization: invalid-percentage # Should be number, not string diff --git a/tests/translator/input/error_function_with_validation_rules.yaml b/tests/translator/input/error_function_with_validation_rules.yaml new file mode 100644 index 0000000000..b2fb448f21 --- /dev/null +++ b/tests/translator/input/error_function_with_validation_rules.yaml @@ -0,0 +1,17 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test validation rules for function resources + +Resources: + # This function has both CapacityProviderConfig and ProvisionedConcurrencyConfig + # which are mutually exclusive, so it should fail validation + FunctionWithValidationError: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: index.handler + Runtime: python3.9 + CapacityProviderConfig: + Arn: arn:aws:lambda:us-west-2:123456789012:capacity-provider/test-provider + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: 10 diff --git a/tests/translator/input/error_function_with_validation_rules_in_globals.yaml b/tests/translator/input/error_function_with_validation_rules_in_globals.yaml new file mode 100644 index 0000000000..91e4b36035 --- /dev/null +++ b/tests/translator/input/error_function_with_validation_rules_in_globals.yaml @@ -0,0 +1,39 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 + +Globals: + Function: + CapacityProviderConfig: + Arn: arn:aws:lambda:us-east-1:123456789012:capacity-provider/test + PerExecutionEnvironmentMaxConcurrency: 10 + +Resources: + GlobalFunction1: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + return { + statusCode: 200, + body: JSON.stringify({ message: "Hello World" }), + }; + }; + Handler: index.handler + Runtime: nodejs18.x + # This should work fine because it's using the global CapacityProviderConfig + + GlobalFunction2: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + return { + statusCode: 200, + body: JSON.stringify({ message: "Hello World" }), + }; + }; + Handler: index.handler + Runtime: nodejs18.x + # This should fail because ProvisionedConcurrencyConfig is mutually exclusive with CapacityProviderConfig + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: 10 diff --git a/tests/translator/input/error_global_capacity_provider_unsupported.yaml b/tests/translator/input/error_global_capacity_provider_unsupported.yaml new file mode 100644 index 0000000000..ae8649750c --- /dev/null +++ b/tests/translator/input/error_global_capacity_provider_unsupported.yaml @@ -0,0 +1,23 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Test unsupported property in CapacityProvider Globals + +Globals: + CapacityProvider: + VpcConfig: + SubnetIds: + - subnet-12345678 + CapacityProviderName: CapacityProviderName-is-not-supported + +Resources: + MinimalCapacityProvider: + Type: AWS::Serverless::CapacityProvider + Properties: + CapacityProviderName: test-capacity-provider + + MinimalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 diff --git a/tests/translator/input/error_version_deletion_policy_without_auto_publish_alias.yaml b/tests/translator/input/error_version_deletion_policy_without_auto_publish_alias.yaml new file mode 100644 index 0000000000..4efdabf288 --- /dev/null +++ b/tests/translator/input/error_version_deletion_policy_without_auto_publish_alias.yaml @@ -0,0 +1,10 @@ +Resources: + MinimalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + DeploymentPreference: + Type: AllAtOnce + VersionDeletionPolicy: Delete diff --git a/tests/translator/input/function_with_alias_version_deletion_policy.yaml b/tests/translator/input/function_with_alias_version_deletion_policy.yaml new file mode 100644 index 0000000000..a0fd455a6e --- /dev/null +++ b/tests/translator/input/function_with_alias_version_deletion_policy.yaml @@ -0,0 +1,10 @@ +Resources: + MinimalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.13 + AutoPublishAlias: live + VersionDescription: sam-testing + VersionDeletionPolicy: Delete diff --git a/tests/translator/input/function_with_capacity_provider_and_autopublish.yaml b/tests/translator/input/function_with_capacity_provider_and_autopublish.yaml new file mode 100644 index 0000000000..3ea2cf91a0 --- /dev/null +++ b/tests/translator/input/function_with_capacity_provider_and_autopublish.yaml @@ -0,0 +1,23 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Function with capacity provider and AutoPublishAlias test + +Resources: + LMIFunctionWithAutoPublish: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + Description: Lambda function with capacity provider and auto publish alias + MemorySize: 512 + Timeout: 30 + AutoPublishAlias: Production + CapacityProviderConfig: + Arn: arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider + PerExecutionEnvironmentMaxConcurrency: 50 + FunctionScalingConfig: + MinExecutionEnvironments: 2 + MaxExecutionEnvironments: 20 + DeploymentPreference: + Type: Linear10PercentEvery1Minute diff --git a/tests/translator/input/function_with_capacity_provider_full.yaml b/tests/translator/input/function_with_capacity_provider_full.yaml new file mode 100644 index 0000000000..f5e9a9c4c6 --- /dev/null +++ b/tests/translator/input/function_with_capacity_provider_full.yaml @@ -0,0 +1,26 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Function with full capacity provider configuration test + +Resources: + FullLMIFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: LMIFunctionWithFullConfig + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + Description: Lambda function with full capacity provider configuration + MemorySize: 512 + Timeout: 30 + Environment: + Variables: + ENVIRONMENT: production + CapacityProviderConfig: + Arn: arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider + PerExecutionEnvironmentMaxConcurrency: 100 + ExecutionEnvironmentMemoryGiBPerVCpu: 4.0 + FunctionScalingConfig: + MinExecutionEnvironments: 5 + MaxExecutionEnvironments: 100 + PublishToLatestPublished: false diff --git a/tests/translator/input/function_with_capacity_provider_minimal.yaml b/tests/translator/input/function_with_capacity_provider_minimal.yaml new file mode 100644 index 0000000000..cab1c364b5 --- /dev/null +++ b/tests/translator/input/function_with_capacity_provider_minimal.yaml @@ -0,0 +1,13 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Function with minimal capacity provider configuration test + +Resources: + MinimalLMIFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.12 + CapacityProviderConfig: + Arn: arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider diff --git a/tests/translator/output/aws-cn/capacity_provider_custom_permissions.json b/tests/translator/output/aws-cn/capacity_provider_custom_permissions.json new file mode 100644 index 0000000000..7cedf6167c --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_custom_permissions.json @@ -0,0 +1,136 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with custom permissions configuration test", + "Resources": { + "CustomPermissionsCapacityProvider": { + "Properties": { + "CapacityProviderName": "custom-permissions-provider", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/capacity_provider_full.json b/tests/translator/output/aws-cn/capacity_provider_full.json new file mode 100644 index 0000000000..6c976f0d6e --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_full.json @@ -0,0 +1,93 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Full CapacityProvider configuration test", + "Resources": { + "FullCapacityProvider": { + "Properties": { + "CapacityProviderName": "customized-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "KMSKeyArn": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "FullCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "Team", + "Value": "Tooling" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678", + "sg-87654321" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "FullCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/capacity_provider_global_with_functions.json b/tests/translator/output/aws-cn/capacity_provider_global_with_functions.json new file mode 100644 index 0000000000..83b98485ca --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_global_with_functions.json @@ -0,0 +1,596 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "IsProd": { + "Fn::Equals": [ + { + "Ref": "Environment" + }, + "prod" + ] + } + }, + "Description": "CapacityProvider with Globals and intrinsic functions test", + "Outputs": { + "CapacityProviderArn": { + "Description": "ARN of the created capacity provider", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-CapacityProviderArn" + } + }, + "Value": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + } + }, + "EnvironmentInfo": { + "Description": "Environment and team information", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-EnvironmentInfo" + } + }, + "Value": { + "Fn::Sub": "${Environment}-${Team}" + } + }, + "Function1Name": { + "Description": "Name of Function 1", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function1Name" + } + }, + "Value": { + "Ref": "GlobalFunction1" + } + }, + "Function2Name": { + "Description": "Name of Function 2", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function2Name" + } + }, + "Value": { + "Ref": "GlobalFunction2" + } + } + }, + "Parameters": { + "Environment": { + "AllowedValues": [ + "dev", + "staging", + "prod" + ], + "Default": "dev", + "Type": "String" + }, + "MaxConcurrency": { + "Default": 100, + "Type": "Number" + }, + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "Team": { + "Default": "serverless-team", + "Type": "String" + } + }, + "Resources": { + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-capacity-provider" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Fn::If": [ + "IsProd", + 20, + 10 + ] + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Fn::If": [ + "IsProd", + 80.0, + 70.0 + ] + } + } + ] + }, + "InstanceRequirements": { + "Architectures": [ + "x86_64", + "arm64" + ], + "ExcludedInstanceTypes": [ + "t2.micro", + "t2.small" + ] + }, + "KMSKeyArn": "some-kms-arn", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "GlobalFunction1": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + }, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": "Function 1 in ${Environment} environment managed by ${Team}" + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-function-1" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 2, + 1 + ] + } + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction1Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction1Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": [ + "Function 2 in ${env} for ${team} team with provider ${provider}", + { + "env": { + "Ref": "Environment" + }, + "provider": { + "Ref": "GlobalCapacityProvider" + }, + "team": { + "Ref": "Team" + } + } + ] + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Join": [ + "-", + [ + { + "Ref": "AWS::StackName" + }, + { + "Ref": "Environment" + }, + "function", + "2" + ] + ] + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction2Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction2AliasDevelopment": { + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "GlobalFunction2Versione5501c4cce", + "Version" + ] + }, + "Name": "Development" + }, + "Type": "AWS::Lambda::Alias" + }, + "GlobalFunction2Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2Versione5501c4cce": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-cn/capacity_provider_minimal.json b/tests/translator/output/aws-cn/capacity_provider_minimal.json new file mode 100644 index 0000000000..82053514b1 --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_minimal.json @@ -0,0 +1,60 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Minimal CapacityProvider configuration test", + "Resources": { + "MinimalCapacityProvider": { + "Properties": { + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MinimalCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MinimalCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/capacity_provider_with_intrinsics.json b/tests/translator/output/aws-cn/capacity_provider_with_intrinsics.json new file mode 100644 index 0000000000..23b39ec2d7 --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_with_intrinsics.json @@ -0,0 +1,162 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with intrinsic functions test", + "Parameters": { + "AllowedInstanceType": { + "Default": "c5.xlarge", + "Type": "String" + }, + "Architecture": { + "Default": "arm64", + "Type": "String" + }, + "CapacityProviderName": { + "Default": "intrinsic-capacity-provider", + "Type": "String" + }, + "ExcludedInstanceType": { + "Default": "t2.micro", + "Type": "String" + }, + "KMSKeyArn": { + "Default": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "Type": "String" + }, + "MaxVCpuCount": { + "Default": 10, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "TargetCPU": { + "Default": 75.0, + "Type": "Number" + }, + "TargetMemory": { + "Default": 81.2, + "Type": "Number" + } + }, + "Resources": { + "IntrinsicCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Ref": "CapacityProviderName" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Ref": "MaxVCpuCount" + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Ref": "TargetCPU" + } + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + { + "Ref": "AllowedInstanceType" + }, + { + "Fn::Join": [ + ".", + [ + "c5", + "2xlarge" + ] + ] + } + ], + "Architectures": [ + { + "Ref": "Architecture" + } + ] + }, + "KMSKeyArn": { + "Ref": "KMSKeyArn" + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "IntrinsicCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Fn::Sub": "${AWS::StackName}-environment" + } + }, + { + "Key": "Team", + "Value": { + "Fn::Sub": "${AWS::StackName}-team" + } + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "IntrinsicCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/capacity_provider_with_mulitple_functions.json b/tests/translator/output/aws-cn/capacity_provider_with_mulitple_functions.json new file mode 100644 index 0000000000..75ec3af64d --- /dev/null +++ b/tests/translator/output/aws-cn/capacity_provider_with_mulitple_functions.json @@ -0,0 +1,470 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Complete template with capacity provider and functions", + "Parameters": { + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Description": "Memory GiB per vCPU for capacity provider", + "Type": "Number" + } + }, + "Resources": { + "BasicLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "BasicLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "BasicLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAlias": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicy": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasDeletePolicyAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeletePolicyDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicyDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasDeletePolicyRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasDeletePolicyVersion640128d35d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "LMIFunctionWithAliasDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyCapacityProvider": { + "Properties": { + "CapacityProviderName": "test-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MyCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MyCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_alias_version_deletion_policy.json b/tests/translator/output/aws-cn/function_with_alias_version_deletion_policy.json new file mode 100644 index 0000000000..8ea94a5fc1 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_alias_version_deletion_policy.json @@ -0,0 +1,82 @@ +{ + "Resources": { + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.13", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MinimalFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MinimalFunctionVersion640128d35d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MinimalFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MinimalFunctionVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "Description": "sam-testing", + "FunctionName": { + "Ref": "MinimalFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_capacity_provider_and_autopublish.json b/tests/translator/output/aws-cn/function_with_capacity_provider_and_autopublish.json new file mode 100644 index 0000000000..f80b631ea9 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_capacity_provider_and_autopublish.json @@ -0,0 +1,174 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with capacity provider and AutoPublishAlias test", + "Resources": { + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublish": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAutoPublishAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishVersion89e69c9a8e", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAutoPublishDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAutoPublishDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAutoPublishRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublishVersion89e69c9a8e": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_capacity_provider_full.json b/tests/translator/output/aws-cn/function_with_capacity_provider_full.json new file mode 100644 index 0000000000..6f1edf59ca --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_capacity_provider_full.json @@ -0,0 +1,80 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with full capacity provider configuration test", + "Resources": { + "FullLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 100 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with full capacity provider configuration", + "Environment": { + "Variables": { + "ENVIRONMENT": "production" + } + }, + "FunctionName": "LMIFunctionWithFullConfig", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 100, + "MinExecutionEnvironments": 5 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "PublishToLatestPublished": false, + "Role": { + "Fn::GetAtt": [ + "FullLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "FullLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_capacity_provider_minimal.json b/tests/translator/output/aws-cn/function_with_capacity_provider_minimal.json new file mode 100644 index 0000000000..77b8c779bf --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_capacity_provider_minimal.json @@ -0,0 +1,64 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with minimal capacity provider configuration test", + "Resources": { + "MinimalLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider" + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_custom_permissions.json b/tests/translator/output/aws-us-gov/capacity_provider_custom_permissions.json new file mode 100644 index 0000000000..7cedf6167c --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_custom_permissions.json @@ -0,0 +1,136 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with custom permissions configuration test", + "Resources": { + "CustomPermissionsCapacityProvider": { + "Properties": { + "CapacityProviderName": "custom-permissions-provider", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_full.json b/tests/translator/output/aws-us-gov/capacity_provider_full.json new file mode 100644 index 0000000000..a56787a80e --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_full.json @@ -0,0 +1,93 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Full CapacityProvider configuration test", + "Resources": { + "FullCapacityProvider": { + "Properties": { + "CapacityProviderName": "customized-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "KMSKeyArn": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "FullCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "Team", + "Value": "Tooling" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678", + "sg-87654321" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "FullCapacityProviderOperatorRole": { + "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/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_global_with_functions.json b/tests/translator/output/aws-us-gov/capacity_provider_global_with_functions.json new file mode 100644 index 0000000000..a241cd279d --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_global_with_functions.json @@ -0,0 +1,596 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "IsProd": { + "Fn::Equals": [ + { + "Ref": "Environment" + }, + "prod" + ] + } + }, + "Description": "CapacityProvider with Globals and intrinsic functions test", + "Outputs": { + "CapacityProviderArn": { + "Description": "ARN of the created capacity provider", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-CapacityProviderArn" + } + }, + "Value": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + } + }, + "EnvironmentInfo": { + "Description": "Environment and team information", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-EnvironmentInfo" + } + }, + "Value": { + "Fn::Sub": "${Environment}-${Team}" + } + }, + "Function1Name": { + "Description": "Name of Function 1", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function1Name" + } + }, + "Value": { + "Ref": "GlobalFunction1" + } + }, + "Function2Name": { + "Description": "Name of Function 2", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function2Name" + } + }, + "Value": { + "Ref": "GlobalFunction2" + } + } + }, + "Parameters": { + "Environment": { + "AllowedValues": [ + "dev", + "staging", + "prod" + ], + "Default": "dev", + "Type": "String" + }, + "MaxConcurrency": { + "Default": 100, + "Type": "Number" + }, + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "Team": { + "Default": "serverless-team", + "Type": "String" + } + }, + "Resources": { + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-capacity-provider" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Fn::If": [ + "IsProd", + 20, + 10 + ] + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Fn::If": [ + "IsProd", + 80.0, + 70.0 + ] + } + } + ] + }, + "InstanceRequirements": { + "Architectures": [ + "x86_64", + "arm64" + ], + "ExcludedInstanceTypes": [ + "t2.micro", + "t2.small" + ] + }, + "KMSKeyArn": "some-kms-arn", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "GlobalFunction1": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + }, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": "Function 1 in ${Environment} environment managed by ${Team}" + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-function-1" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 2, + 1 + ] + } + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction1Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction1Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": [ + "Function 2 in ${env} for ${team} team with provider ${provider}", + { + "env": { + "Ref": "Environment" + }, + "provider": { + "Ref": "GlobalCapacityProvider" + }, + "team": { + "Ref": "Team" + } + } + ] + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Join": [ + "-", + [ + { + "Ref": "AWS::StackName" + }, + { + "Ref": "Environment" + }, + "function", + "2" + ] + ] + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction2Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction2AliasDevelopment": { + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "GlobalFunction2Versione5501c4cce", + "Version" + ] + }, + "Name": "Development" + }, + "Type": "AWS::Lambda::Alias" + }, + "GlobalFunction2Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2Versione5501c4cce": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_minimal.json b/tests/translator/output/aws-us-gov/capacity_provider_minimal.json new file mode 100644 index 0000000000..a48181742f --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_minimal.json @@ -0,0 +1,60 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Minimal CapacityProvider configuration test", + "Resources": { + "MinimalCapacityProvider": { + "Properties": { + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MinimalCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MinimalCapacityProviderOperatorRole": { + "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/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_with_intrinsics.json b/tests/translator/output/aws-us-gov/capacity_provider_with_intrinsics.json new file mode 100644 index 0000000000..c43f074d6b --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_with_intrinsics.json @@ -0,0 +1,162 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with intrinsic functions test", + "Parameters": { + "AllowedInstanceType": { + "Default": "c5.xlarge", + "Type": "String" + }, + "Architecture": { + "Default": "arm64", + "Type": "String" + }, + "CapacityProviderName": { + "Default": "intrinsic-capacity-provider", + "Type": "String" + }, + "ExcludedInstanceType": { + "Default": "t2.micro", + "Type": "String" + }, + "KMSKeyArn": { + "Default": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "Type": "String" + }, + "MaxVCpuCount": { + "Default": 10, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "TargetCPU": { + "Default": 75.0, + "Type": "Number" + }, + "TargetMemory": { + "Default": 81.2, + "Type": "Number" + } + }, + "Resources": { + "IntrinsicCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Ref": "CapacityProviderName" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Ref": "MaxVCpuCount" + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Ref": "TargetCPU" + } + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + { + "Ref": "AllowedInstanceType" + }, + { + "Fn::Join": [ + ".", + [ + "c5", + "2xlarge" + ] + ] + } + ], + "Architectures": [ + { + "Ref": "Architecture" + } + ] + }, + "KMSKeyArn": { + "Ref": "KMSKeyArn" + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "IntrinsicCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Fn::Sub": "${AWS::StackName}-environment" + } + }, + { + "Key": "Team", + "Value": { + "Fn::Sub": "${AWS::StackName}-team" + } + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "IntrinsicCapacityProviderOperatorRole": { + "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/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/capacity_provider_with_mulitple_functions.json b/tests/translator/output/aws-us-gov/capacity_provider_with_mulitple_functions.json new file mode 100644 index 0000000000..18d540a59e --- /dev/null +++ b/tests/translator/output/aws-us-gov/capacity_provider_with_mulitple_functions.json @@ -0,0 +1,470 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Complete template with capacity provider and functions", + "Parameters": { + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Description": "Memory GiB per vCPU for capacity provider", + "Type": "Number" + } + }, + "Resources": { + "BasicLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "BasicLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "BasicLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAlias": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicy": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasDeletePolicyAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeletePolicyDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicyDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasDeletePolicyRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasDeletePolicyVersion640128d35d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "LMIFunctionWithAliasDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyCapacityProvider": { + "Properties": { + "CapacityProviderName": "test-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MyCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MyCapacityProviderOperatorRole": { + "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/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_alias_version_deletion_policy.json b/tests/translator/output/aws-us-gov/function_with_alias_version_deletion_policy.json new file mode 100644 index 0000000000..d91534358c --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_alias_version_deletion_policy.json @@ -0,0 +1,82 @@ +{ + "Resources": { + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.13", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MinimalFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MinimalFunctionVersion640128d35d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MinimalFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MinimalFunctionVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "Description": "sam-testing", + "FunctionName": { + "Ref": "MinimalFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_capacity_provider_and_autopublish.json b/tests/translator/output/aws-us-gov/function_with_capacity_provider_and_autopublish.json new file mode 100644 index 0000000000..87d462acee --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_capacity_provider_and_autopublish.json @@ -0,0 +1,174 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with capacity provider and AutoPublishAlias test", + "Resources": { + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublish": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAutoPublishAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishVersion89e69c9a8e", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAutoPublishDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAutoPublishDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAutoPublishRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublishVersion89e69c9a8e": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_capacity_provider_full.json b/tests/translator/output/aws-us-gov/function_with_capacity_provider_full.json new file mode 100644 index 0000000000..e5ec8fc11d --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_capacity_provider_full.json @@ -0,0 +1,80 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with full capacity provider configuration test", + "Resources": { + "FullLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 100 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with full capacity provider configuration", + "Environment": { + "Variables": { + "ENVIRONMENT": "production" + } + }, + "FunctionName": "LMIFunctionWithFullConfig", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 100, + "MinExecutionEnvironments": 5 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "PublishToLatestPublished": false, + "Role": { + "Fn::GetAtt": [ + "FullLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "FullLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_capacity_provider_minimal.json b/tests/translator/output/aws-us-gov/function_with_capacity_provider_minimal.json new file mode 100644 index 0000000000..7e6443baee --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_capacity_provider_minimal.json @@ -0,0 +1,64 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with minimal capacity provider configuration test", + "Resources": { + "MinimalLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider" + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/capacity_provider_custom_permissions.json b/tests/translator/output/capacity_provider_custom_permissions.json new file mode 100644 index 0000000000..7cedf6167c --- /dev/null +++ b/tests/translator/output/capacity_provider_custom_permissions.json @@ -0,0 +1,136 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with custom permissions configuration test", + "Resources": { + "CustomPermissionsCapacityProvider": { + "Properties": { + "CapacityProviderName": "custom-permissions-provider", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/capacity_provider_full.json b/tests/translator/output/capacity_provider_full.json new file mode 100644 index 0000000000..2eedfafd26 --- /dev/null +++ b/tests/translator/output/capacity_provider_full.json @@ -0,0 +1,93 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Full CapacityProvider configuration test", + "Resources": { + "FullCapacityProvider": { + "Properties": { + "CapacityProviderName": "customized-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "KMSKeyArn": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "FullCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "Team", + "Value": "Tooling" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678", + "sg-87654321" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "FullCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/capacity_provider_global_with_functions.json b/tests/translator/output/capacity_provider_global_with_functions.json new file mode 100644 index 0000000000..41dbf901a5 --- /dev/null +++ b/tests/translator/output/capacity_provider_global_with_functions.json @@ -0,0 +1,596 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "IsProd": { + "Fn::Equals": [ + { + "Ref": "Environment" + }, + "prod" + ] + } + }, + "Description": "CapacityProvider with Globals and intrinsic functions test", + "Outputs": { + "CapacityProviderArn": { + "Description": "ARN of the created capacity provider", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-CapacityProviderArn" + } + }, + "Value": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + } + }, + "EnvironmentInfo": { + "Description": "Environment and team information", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-EnvironmentInfo" + } + }, + "Value": { + "Fn::Sub": "${Environment}-${Team}" + } + }, + "Function1Name": { + "Description": "Name of Function 1", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function1Name" + } + }, + "Value": { + "Ref": "GlobalFunction1" + } + }, + "Function2Name": { + "Description": "Name of Function 2", + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Function2Name" + } + }, + "Value": { + "Ref": "GlobalFunction2" + } + } + }, + "Parameters": { + "Environment": { + "AllowedValues": [ + "dev", + "staging", + "prod" + ], + "Default": "dev", + "Type": "String" + }, + "MaxConcurrency": { + "Default": 100, + "Type": "Number" + }, + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "Team": { + "Default": "serverless-team", + "Type": "String" + } + }, + "Resources": { + "CustomPermissionsCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:TerminateInstances", + "ec2:RunInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances", + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:instance/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:network-interface/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:volume/*" + } + ] + }, + { + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeCapacityReservations", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceTypes", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:RunInstances", + "ec2:CreateNetworkInterface" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:subnet/*" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:security-group/*" + } + ] + }, + { + "Action": [ + "ec2:RunInstances" + ], + "Condition": { + "Bool": { + "ec2:Public": "true" + } + }, + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:ec2:*:*:image/*" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CapacityProviderOperatorRolePolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-capacity-provider" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Fn::If": [ + "IsProd", + 20, + 10 + ] + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Fn::If": [ + "IsProd", + 80.0, + 70.0 + ] + } + } + ] + }, + "InstanceRequirements": { + "Architectures": [ + "x86_64", + "arm64" + ], + "ExcludedInstanceTypes": [ + "t2.micro", + "t2.small" + ] + }, + "KMSKeyArn": "some-kms-arn", + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "CustomPermissionsCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "GlobalFunction1": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + }, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": "Function 1 in ${Environment} environment managed by ${Team}" + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Sub": "${AWS::StackName}-${Environment}-function-1" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 2, + 1 + ] + } + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction1Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction1Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "GlobalCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": { + "Ref": "MaxConcurrency" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": { + "Fn::Sub": [ + "Function 2 in ${env} for ${team} team with provider ${provider}", + { + "env": { + "Ref": "Environment" + }, + "provider": { + "Ref": "GlobalCapacityProvider" + }, + "team": { + "Ref": "Team" + } + } + ] + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "Environment" + }, + "TEAM": { + "Ref": "Team" + } + } + }, + "FunctionName": { + "Fn::Join": [ + "-", + [ + { + "Ref": "AWS::StackName" + }, + { + "Ref": "Environment" + }, + "function", + "2" + ] + ] + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + }, + "Handler": "index.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "GlobalFunction2Role", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "GlobalFunction2AliasDevelopment": { + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "GlobalFunction2Versione5501c4cce", + "Version" + ] + }, + "Name": "Development" + }, + "Type": "AWS::Lambda::Alias" + }, + "GlobalFunction2Role": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + }, + { + "Key": "Environment", + "Value": { + "Ref": "Environment" + } + }, + { + "Key": "Team", + "Value": { + "Ref": "Team" + } + }, + { + "Key": "ManagedBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "GlobalFunction2Versione5501c4cce": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "GlobalFunction2" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": { + "Fn::If": [ + "IsProd", + 50, + 10 + ] + }, + "MinExecutionEnvironments": 3 + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/capacity_provider_minimal.json b/tests/translator/output/capacity_provider_minimal.json new file mode 100644 index 0000000000..b2c936f4fe --- /dev/null +++ b/tests/translator/output/capacity_provider_minimal.json @@ -0,0 +1,60 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Minimal CapacityProvider configuration test", + "Resources": { + "MinimalCapacityProvider": { + "Properties": { + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MinimalCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MinimalCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/capacity_provider_with_intrinsics.json b/tests/translator/output/capacity_provider_with_intrinsics.json new file mode 100644 index 0000000000..46e89ae046 --- /dev/null +++ b/tests/translator/output/capacity_provider_with_intrinsics.json @@ -0,0 +1,162 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "CapacityProvider with intrinsic functions test", + "Parameters": { + "AllowedInstanceType": { + "Default": "c5.xlarge", + "Type": "String" + }, + "Architecture": { + "Default": "arm64", + "Type": "String" + }, + "CapacityProviderName": { + "Default": "intrinsic-capacity-provider", + "Type": "String" + }, + "ExcludedInstanceType": { + "Default": "t2.micro", + "Type": "String" + }, + "KMSKeyArn": { + "Default": "arn:aws:kms:us-east-1:123456789012:key/abcd1234-ef56-gh78-ij90-klmnopqrstuv", + "Type": "String" + }, + "MaxVCpuCount": { + "Default": 10, + "Type": "Number" + }, + "SecurityGroupId": { + "Default": "sg-12345678", + "Type": "String" + }, + "SubnetId": { + "Default": "subnet-12345678", + "Type": "String" + }, + "TargetCPU": { + "Default": 75.0, + "Type": "Number" + }, + "TargetMemory": { + "Default": 81.2, + "Type": "Number" + } + }, + "Resources": { + "IntrinsicCapacityProvider": { + "Properties": { + "CapacityProviderName": { + "Ref": "CapacityProviderName" + }, + "CapacityProviderScalingConfig": { + "MaxVCpuCount": { + "Ref": "MaxVCpuCount" + }, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": { + "Ref": "TargetCPU" + } + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + { + "Ref": "AllowedInstanceType" + }, + { + "Fn::Join": [ + ".", + [ + "c5", + "2xlarge" + ] + ] + } + ], + "Architectures": [ + { + "Ref": "Architecture" + } + ] + }, + "KMSKeyArn": { + "Ref": "KMSKeyArn" + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "IntrinsicCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "Environment", + "Value": { + "Fn::Sub": "${AWS::StackName}-environment" + } + }, + { + "Key": "Team", + "Value": { + "Fn::Sub": "${AWS::StackName}-team" + } + }, + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + { + "Ref": "SecurityGroupId" + } + ], + "SubnetIds": [ + { + "Ref": "SubnetId" + } + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "IntrinsicCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/capacity_provider_with_mulitple_functions.json b/tests/translator/output/capacity_provider_with_mulitple_functions.json new file mode 100644 index 0000000000..b56087fd10 --- /dev/null +++ b/tests/translator/output/capacity_provider_with_mulitple_functions.json @@ -0,0 +1,470 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Complete template with capacity provider and functions", + "Parameters": { + "MemoryGiBPerVCpu": { + "Default": 2.5, + "Description": "Memory GiB per vCPU for capacity provider", + "Type": "Number" + } + }, + "Resources": { + "BasicLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": { + "Ref": "MemoryGiBPerVCpu" + } + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "BasicLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "BasicLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAlias": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicy": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": { + "Fn::GetAtt": [ + "MyCapacityProvider", + "Arn" + ] + }, + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAliasDeletePolicyAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAliasDeletePolicyVersion640128d35d", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAliasDeletePolicyDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAliasDeletePolicyDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasDeletePolicyRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasDeletePolicyVersion640128d35d": { + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAliasDeletePolicy" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "LMIFunctionWithAliasDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAliasRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAliasVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAlias" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "MyCapacityProvider": { + "Properties": { + "CapacityProviderName": "test-capacity-provider", + "CapacityProviderScalingConfig": { + "MaxVCpuCount": 10, + "ScalingMode": "Manual", + "ScalingPolicies": [ + { + "PredefinedMetricType": "LambdaCapacityProviderAverageCPUUtilization", + "TargetValue": 75.0 + } + ] + }, + "InstanceRequirements": { + "AllowedInstanceTypes": [ + "c5.xlarge", + "c5.2xlarge" + ], + "Architectures": [ + "arm64" + ] + }, + "PermissionsConfig": { + "CapacityProviderOperatorRoleArn": { + "Fn::GetAtt": [ + "MyCapacityProviderOperatorRole", + "Arn" + ] + } + }, + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "VpcConfig": { + "SecurityGroupIds": [ + "sg-12345678" + ], + "SubnetIds": [ + "subnet-12345678" + ] + } + }, + "Type": "AWS::Lambda::CapacityProvider" + }, + "MyCapacityProviderOperatorRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/error_auto_publish_alias_version_deletion_policy.json b/tests/translator/output/error_auto_publish_alias_version_deletion_policy.json new file mode 100644 index 0000000000..412746461b --- /dev/null +++ b/tests/translator/output/error_auto_publish_alias_version_deletion_policy.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MinimalFunction] is invalid. ", + "Property 'VersionDeletionPolicy' should be a one of the strings: 'Delete' or 'Retain'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MinimalFunction] is invalid. Property 'VersionDeletionPolicy' should be a one of the strings: 'Delete' or 'Retain'." +} diff --git a/tests/translator/output/error_capacity_provider_missing_subnet_ids.json b/tests/translator/output/error_capacity_provider_missing_subnet_ids.json new file mode 100644 index 0000000000..c37e8759df --- /dev/null +++ b/tests/translator/output/error_capacity_provider_missing_subnet_ids.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderMissingSubnetIds] is invalid. ", + "Property 'VpcConfig.SubnetIds' is required." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderMissingSubnetIds] is invalid. Property 'VpcConfig.SubnetIds' is required." +} diff --git a/tests/translator/output/error_capacity_provider_missing_vpc_config.json b/tests/translator/output/error_capacity_provider_missing_vpc_config.json new file mode 100644 index 0000000000..506eafb482 --- /dev/null +++ b/tests/translator/output/error_capacity_provider_missing_vpc_config.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderMissingVpcConfig] is invalid. ", + "Missing required property 'VpcConfig'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderMissingVpcConfig] is invalid. Missing required property 'VpcConfig'.", + "errors": [ + { + "errorMessage": "Resource with id [CapacityProviderMissingVpcConfig] is invalid. Missing required property 'VpcConfig'." + } + ] +} diff --git a/tests/translator/output/error_capacity_provider_multiple_resources_validation.json b/tests/translator/output/error_capacity_provider_multiple_resources_validation.json new file mode 100644 index 0000000000..e68044bb0a --- /dev/null +++ b/tests/translator/output/error_capacity_provider_multiple_resources_validation.json @@ -0,0 +1,18 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 4. ", + "Resource with id [CapacityProvider1] is invalid. ", + "Missing required property 'VpcConfig'. ", + "Resource with id [CapacityProvider2] is invalid. ", + "Property 'VpcConfig.SubnetIds' is required. ", + "Resource with id [CapacityProvider3] is invalid. ", + "Property 'VpcConfig.SecurityGroupIds' value is not a valid list. ", + "Property 'VpcConfig.SubnetIds' value is not a valid list. ", + "Property 'ScalingConfig.MaxVCpuCount' value must be dictionary or integer. ", + "Resource with id [CapacityProvider4] is invalid. ", + "Property 'VpcConfig.InvalidProperty' is an invalid property. ", + "Property 'ScalingConfig.AverageCPUUtilization' value must be dictionary or number." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 4. Resource with id [CapacityProvider1] is invalid. Missing required property 'VpcConfig'. Resource with id [CapacityProvider2] is invalid. Property 'VpcConfig.SubnetIds' is required. Resource with id [CapacityProvider3] is invalid. Property 'VpcConfig.SecurityGroupIds' value is not a valid list. Property 'VpcConfig.SubnetIds' value is not a valid list. Property 'ScalingConfig.MaxVCpuCount' value must be dictionary or integer. Resource with id [CapacityProvider4] is invalid. Property 'VpcConfig.InvalidProperty' is an invalid property. Property 'ScalingConfig.AverageCPUUtilization' value must be dictionary or number." +} diff --git a/tests/translator/output/error_capacity_provider_mutually_exclusive_instance_types.json b/tests/translator/output/error_capacity_provider_mutually_exclusive_instance_types.json new file mode 100644 index 0000000000..12dd4c8639 --- /dev/null +++ b/tests/translator/output/error_capacity_provider_mutually_exclusive_instance_types.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderWithValidationError] is invalid. ", + "Cannot specify 'InstanceRequirements.AllowedTypes' and 'InstanceRequirements.ExcludedTypes' together." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderWithValidationError] is invalid. Cannot specify 'InstanceRequirements.AllowedTypes' and 'InstanceRequirements.ExcludedTypes' together." +} diff --git a/tests/translator/output/error_capacity_provider_typo_properties.json b/tests/translator/output/error_capacity_provider_typo_properties.json new file mode 100644 index 0000000000..eb48663da1 --- /dev/null +++ b/tests/translator/output/error_capacity_provider_typo_properties.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderTypoProperties] is invalid. ", + "property CapacityProviderNam not defined for resource of type AWS::Serverless::CapacityProvider" + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderTypoProperties] is invalid. property CapacityProviderNam not defined for resource of type AWS::Serverless::CapacityProvider" +} diff --git a/tests/translator/output/error_capacity_provider_unknown_properties.json b/tests/translator/output/error_capacity_provider_unknown_properties.json new file mode 100644 index 0000000000..4b7e4a310a --- /dev/null +++ b/tests/translator/output/error_capacity_provider_unknown_properties.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderUnknownProperties] is invalid. ", + "property UnknownProperty not defined for resource of type AWS::Serverless::CapacityProvider" + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderUnknownProperties] is invalid. property UnknownProperty not defined for resource of type AWS::Serverless::CapacityProvider" +} diff --git a/tests/translator/output/error_capacity_provider_wrong_types.json b/tests/translator/output/error_capacity_provider_wrong_types.json new file mode 100644 index 0000000000..756c826449 --- /dev/null +++ b/tests/translator/output/error_capacity_provider_wrong_types.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CapacityProviderWrongTypes] is invalid. ", + "Property 'Tags' should be a map." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CapacityProviderWrongTypes] is invalid. Property 'Tags' should be a map.", + "errors": [ + { + "errorMessage": "Resource with id [CapacityProviderWrongTypes] is invalid. Property 'Tags' should be a map." + } + ] +} diff --git a/tests/translator/output/error_function_with_validation_rules.json b/tests/translator/output/error_function_with_validation_rules.json new file mode 100644 index 0000000000..21579f1655 --- /dev/null +++ b/tests/translator/output/error_function_with_validation_rules.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [FunctionWithValidationError] is invalid. ", + "Cannot specify 'CapacityProviderConfig' and 'ProvisionedConcurrencyConfig' together." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FunctionWithValidationError] is invalid. Cannot specify 'CapacityProviderConfig' and 'ProvisionedConcurrencyConfig' together." +} diff --git a/tests/translator/output/error_function_with_validation_rules_in_globals.json b/tests/translator/output/error_function_with_validation_rules_in_globals.json new file mode 100644 index 0000000000..dc5b45abb4 --- /dev/null +++ b/tests/translator/output/error_function_with_validation_rules_in_globals.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [GlobalFunction2] is invalid. ", + "Cannot specify 'CapacityProviderConfig' and 'ProvisionedConcurrencyConfig' together." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [GlobalFunction2] is invalid. Cannot specify 'CapacityProviderConfig' and 'ProvisionedConcurrencyConfig' together." +} diff --git a/tests/translator/output/error_global_capacity_provider_unsupported.json b/tests/translator/output/error_global_capacity_provider_unsupported.json new file mode 100644 index 0000000000..4838c61012 --- /dev/null +++ b/tests/translator/output/error_global_capacity_provider_unsupported.json @@ -0,0 +1,10 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "'Globals' section is invalid. ", + "'CapacityProviderName' is not a supported property of 'CapacityProvider'. ", + "Must be one of the following values - ['VpcConfig', 'OperatorRole', 'Tags', 'InstanceRequirements', 'ScalingConfig', 'KMSKeyArn', 'PropagateTags']" + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'CapacityProviderName' is not a supported property of 'CapacityProvider'. Must be one of the following values - ['VpcConfig', 'OperatorRole', 'Tags', 'InstanceRequirements', 'ScalingConfig', 'KMSKeyArn', 'PropagateTags']" +} diff --git a/tests/translator/output/error_globals_unsupported_property.json b/tests/translator/output/error_globals_unsupported_property.json index b3e28e3c76..cd49621c3e 100644 --- a/tests/translator/output/error_globals_unsupported_property.json +++ b/tests/translator/output/error_globals_unsupported_property.json @@ -4,7 +4,7 @@ "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', 'PropagateTags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'AutoPublishAliasAllProperties', 'Layers', 'DeploymentPreference', 'RolePath', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures', 'SnapStart', 'EphemeralStorage', 'FunctionUrlConfig', 'LoggingConfig']" + "Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'PropagateTags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'AutoPublishAliasAllProperties', 'Layers', 'DeploymentPreference', 'RolePath', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures', 'SnapStart', 'EphemeralStorage', 'FunctionUrlConfig', 'RuntimeManagementConfig', 'LoggingConfig', 'RecursiveLoop', 'SourceKMSKeyArn']" ], - "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', 'PropagateTags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'AutoPublishAliasAllProperties', 'Layers', 'DeploymentPreference', 'RolePath', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures', 'SnapStart', 'EphemeralStorage', 'FunctionUrlConfig', 'LoggingConfig']" + "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', 'PropagateTags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'AutoPublishAliasAllProperties', 'Layers', 'DeploymentPreference', 'RolePath', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn', 'Architectures', 'SnapStart', 'EphemeralStorage', 'FunctionUrlConfig', 'RuntimeManagementConfig', 'LoggingConfig', 'RecursiveLoop', 'SourceKMSKeyArn']" } diff --git a/tests/translator/output/error_version_deletion_policy_without_auto_publish_alias.json b/tests/translator/output/error_version_deletion_policy_without_auto_publish_alias.json new file mode 100644 index 0000000000..92eeb0ea85 --- /dev/null +++ b/tests/translator/output/error_version_deletion_policy_without_auto_publish_alias.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MinimalFunction] is invalid. ", + "'VersionDeletionPolicy' requires 'AutoPublishAlias'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MinimalFunction] is invalid. 'VersionDeletionPolicy' requires 'AutoPublishAlias'." +} diff --git a/tests/translator/output/function_with_alias_version_deletion_policy.json b/tests/translator/output/function_with_alias_version_deletion_policy.json new file mode 100644 index 0000000000..57fe6072fd --- /dev/null +++ b/tests/translator/output/function_with_alias_version_deletion_policy.json @@ -0,0 +1,82 @@ +{ + "Resources": { + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.13", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalFunctionAliaslive": { + "Properties": { + "FunctionName": { + "Ref": "MinimalFunction" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MinimalFunctionVersion640128d35d", + "Version" + ] + }, + "Name": "live" + }, + "Type": "AWS::Lambda::Alias" + }, + "MinimalFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MinimalFunctionVersion640128d35d": { + "DeletionPolicy": "Delete", + "Properties": { + "Description": "sam-testing", + "FunctionName": { + "Ref": "MinimalFunction" + } + }, + "Type": "AWS::Lambda::Version" + } + } +} diff --git a/tests/translator/output/function_with_capacity_provider_and_autopublish.json b/tests/translator/output/function_with_capacity_provider_and_autopublish.json new file mode 100644 index 0000000000..b89dbf4456 --- /dev/null +++ b/tests/translator/output/function_with_capacity_provider_and_autopublish.json @@ -0,0 +1,174 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with capacity provider and AutoPublishAlias test", + "Resources": { + "CodeDeployServiceRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "codedeploy.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublish": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "PerExecutionEnvironmentMaxConcurrency": 50 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with capacity provider and auto publish alias", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "Role": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "LMIFunctionWithAutoPublishAliasProduction": { + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "LMIFunctionWithAutoPublishVersion89e69c9a8e", + "Version" + ] + }, + "Name": "Production" + }, + "Type": "AWS::Lambda::Alias", + "UpdatePolicy": { + "CodeDeployLambdaAliasUpdate": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "DeploymentGroupName": { + "Ref": "LMIFunctionWithAutoPublishDeploymentGroup" + } + } + } + }, + "LMIFunctionWithAutoPublishDeploymentGroup": { + "Properties": { + "ApplicationName": { + "Ref": "ServerlessDeploymentApplication" + }, + "AutoRollbackConfiguration": { + "Enabled": true, + "Events": [ + "DEPLOYMENT_FAILURE", + "DEPLOYMENT_STOP_ON_ALARM", + "DEPLOYMENT_STOP_ON_REQUEST" + ] + }, + "DeploymentConfigName": { + "Fn::Sub": [ + "CodeDeployDefault.Lambda${ConfigName}", + { + "ConfigName": "Linear10PercentEvery1Minute" + } + ] + }, + "DeploymentStyle": { + "DeploymentOption": "WITH_TRAFFIC_CONTROL", + "DeploymentType": "BLUE_GREEN" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "CodeDeployServiceRole", + "Arn" + ] + } + }, + "Type": "AWS::CodeDeploy::DeploymentGroup" + }, + "LMIFunctionWithAutoPublishRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "LMIFunctionWithAutoPublishVersion89e69c9a8e": { + "DeletionPolicy": "Delete", + "Properties": { + "FunctionName": { + "Ref": "LMIFunctionWithAutoPublish" + }, + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 20, + "MinExecutionEnvironments": 2 + } + }, + "Type": "AWS::Lambda::Version" + }, + "ServerlessDeploymentApplication": { + "Properties": { + "ComputePlatform": "Lambda" + }, + "Type": "AWS::CodeDeploy::Application" + } + } +} diff --git a/tests/translator/output/function_with_capacity_provider_full.json b/tests/translator/output/function_with_capacity_provider_full.json new file mode 100644 index 0000000000..e922c5ceaf --- /dev/null +++ b/tests/translator/output/function_with_capacity_provider_full.json @@ -0,0 +1,80 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with full capacity provider configuration test", + "Resources": { + "FullLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider", + "ExecutionEnvironmentMemoryGiBPerVCpu": 4, + "PerExecutionEnvironmentMaxConcurrency": 100 + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "Lambda function with full capacity provider configuration", + "Environment": { + "Variables": { + "ENVIRONMENT": "production" + } + }, + "FunctionName": "LMIFunctionWithFullConfig", + "FunctionScalingConfig": { + "MaxExecutionEnvironments": 100, + "MinExecutionEnvironments": 5 + }, + "Handler": "hello.handler", + "MemorySize": 512, + "PublishToLatestPublished": false, + "Role": { + "Fn::GetAtt": [ + "FullLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 30 + }, + "Type": "AWS::Lambda::Function" + }, + "FullLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/function_with_capacity_provider_minimal.json b/tests/translator/output/function_with_capacity_provider_minimal.json new file mode 100644 index 0000000000..2fc4e979f9 --- /dev/null +++ b/tests/translator/output/function_with_capacity_provider_minimal.json @@ -0,0 +1,64 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Function with minimal capacity provider configuration test", + "Resources": { + "MinimalLMIFunction": { + "Properties": { + "CapacityProviderConfig": { + "LambdaManagedInstancesCapacityProviderConfig": { + "CapacityProviderArn": "arn:aws:lambda:us-east-1:123456789012:capacity-provider/test-capacity-provider" + } + }, + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalLMIFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.12", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MinimalLMIFunctionRole": { + "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" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +}