diff --git a/.cfnlintrc.yaml b/.cfnlintrc.yaml index c4ab0b561d..fee4c28be9 100644 --- a/.cfnlintrc.yaml +++ b/.cfnlintrc.yaml @@ -144,6 +144,10 @@ 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/**/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 + - tests/translator/output/**/function_with_tenancy_config_global.json # cfnlint is not updated to recognize the TenancyConfig property ignore_checks: - E2531 # Deprecated runtime; not relevant for transform tests diff --git a/integration/resources/expected/single/basic_function_with_tenancy_config.json b/integration/resources/expected/single/basic_function_with_tenancy_config.json new file mode 100644 index 0000000000..d4dfecb350 --- /dev/null +++ b/integration/resources/expected/single/basic_function_with_tenancy_config.json @@ -0,0 +1,10 @@ +[ + { + "LogicalResourceId": "MyLambdaFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyLambdaFunctionRole", + "ResourceType": "AWS::IAM::Role" + } +] diff --git a/integration/resources/templates/single/basic_function_with_tenancy_config.yaml b/integration/resources/templates/single/basic_function_with_tenancy_config.yaml new file mode 100644 index 0000000000..a87100dec6 --- /dev/null +++ b/integration/resources/templates/single/basic_function_with_tenancy_config.yaml @@ -0,0 +1,15 @@ +Resources: + MyLambdaFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs18.x + CodeUri: ${codeuri} + MemorySize: 128 + TenancyConfig: + TenantIsolationMode: PER_TENANT + Policies: + - AWSLambdaRole + - AmazonS3ReadOnlyAccess +Metadata: + SamTransformTest: true diff --git a/integration/single/test_basic_function.py b/integration/single/test_basic_function.py index 8e7cc3aee9..598a386825 100644 --- a/integration/single/test_basic_function.py +++ b/integration/single/test_basic_function.py @@ -392,3 +392,24 @@ def _assert_invoke(self, lambda_client, function_name, qualifier=None, expected_ def _verify_get_request(self, url, expected_text): response = self.verify_get_request_response(url, 200) self.assertEqual(response.text, expected_text) + + # @skipIf(current_region_does_not_support([MULTI_TENANCY]), "Multi-tenancy is not supported in this testing region") + @skipIf(True, "Multi-tenancy feature is not available to test yet") + def test_basic_function_with_tenancy_config(self): + """ + Creates a basic lambda function with TenancyConfig + """ + self.create_and_verify_stack("single/basic_function_with_tenancy_config") + + lambda_client = self.client_provider.lambda_client + function_name = self.get_physical_id_by_type("AWS::Lambda::Function") + + # Get function configuration + function_config = lambda_client.get_function_configuration(FunctionName=function_name) + + # Verify TenancyConfig is set correctly + self.assertEqual( + function_config["TenancyConfig"]["TenantIsolationMode"], + "PER_TENANT", + "Expected TenantIsolationMode to be PER_TENANT", + ) diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index 9bdb121629..a0a65a3fb1 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.101.0" +__version__ = "1.102.0" diff --git a/samtranslator/internal/schema_source/aws_serverless_function.py b/samtranslator/internal/schema_source/aws_serverless_function.py index bd60e740bc..cca8559bcf 100644 --- a/samtranslator/internal/schema_source/aws_serverless_function.py +++ b/samtranslator/internal/schema_source/aws_serverless_function.py @@ -522,6 +522,7 @@ class ScheduleV2Event(BaseModel): LoggingConfig = Optional[PassThroughProp] # TODO: add documentation RecursiveLoop = Optional[PassThroughProp] SourceKMSKeyArn = Optional[PassThroughProp] +TenancyConfig = Optional[PassThroughProp] class Properties(BaseModel): @@ -650,6 +651,7 @@ class Properties(BaseModel): LoggingConfig: Optional[PassThroughProp] # TODO: add documentation RecursiveLoop: Optional[PassThroughProp] # TODO: add documentation SourceKMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + TenancyConfig: Optional[PassThroughProp] # TODO: add documentation class Globals(BaseModel): @@ -710,6 +712,7 @@ class Globals(BaseModel): LoggingConfig: Optional[PassThroughProp] # TODO: add documentation RecursiveLoop: Optional[PassThroughProp] # TODO: add documentation SourceKMSKeyArn: Optional[PassThroughProp] # TODO: add documentation + TenancyConfig: Optional[PassThroughProp] # TODO: add documentation class Resource(ResourceAttributes): diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index c6fecd242e..e591277238 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -36,6 +36,7 @@ class LambdaFunction(Resource): "RuntimeManagementConfig": GeneratedProperty(), "LoggingConfig": GeneratedProperty(), "RecursiveLoop": GeneratedProperty(), + "TenancyConfig": GeneratedProperty(), } Code: Dict[str, Any] @@ -64,6 +65,7 @@ class LambdaFunction(Resource): RuntimeManagementConfig: Optional[Dict[str, Any]] LoggingConfig: Optional[Dict[str, Any]] RecursiveLoop: Optional[str] + TenancyConfig: Optional[Dict[str, Any]] runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")} diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 70e7ef6750..3cafe9634d 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -184,6 +184,7 @@ class SamFunction(SamResourceMacro): "LoggingConfig": PassThroughProperty(False), "RecursiveLoop": PassThroughProperty(False), "SourceKMSKeyArn": PassThroughProperty(False), + "TenancyConfig": PassThroughProperty(False), } FunctionName: Optional[Intrinsicable[str]] @@ -228,6 +229,7 @@ class SamFunction(SamResourceMacro): LoggingConfig: Optional[Dict[str, Any]] RecursiveLoop: Optional[str] SourceKMSKeyArn: Optional[str] + TenancyConfig: Optional[Dict[str, Any]] event_resolver = ResourceTypeResolver( samtranslator.model.eventsources, @@ -277,6 +279,8 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P if self.DeadLetterQueue: self._validate_dlq(self.DeadLetterQueue) + self._validate_tenancy_config_compatibility() + lambda_function = self._construct_lambda_function(intrinsics_resolver) resources.append(lambda_function) @@ -572,6 +576,37 @@ def _get_resolved_alias_name( return resolved_alias_name + def _validate_tenancy_config_compatibility(self) -> None: + if not self.TenancyConfig: + return + + if self.ProvisionedConcurrencyConfig: + raise InvalidResourceException( + self.logical_id, + "Provisioned concurrency is not supported for functions enabled with tenancy configuration.", + ) + + if self.FunctionUrlConfig: + raise InvalidResourceException( + self.logical_id, + "Function URL is not supported for functions enabled with tenancy configuration.", + ) + + if self.SnapStart: + raise InvalidResourceException( + self.logical_id, + "SnapStart is not supported for functions enabled with tenancy configuration.", + ) + + if self.Events: + for event in self.Events.values(): + event_type = event.get("Type") + if event_type not in ["Api", "HttpApi"]: + raise InvalidResourceException( + self.logical_id, + f"Event source '{event_type}' is not supported for functions enabled with tenancy configuration. Only Api and HttpApi event sources are supported.", + ) + def _construct_lambda_function(self, intrinsics_resolver: IntrinsicsResolver) -> LambdaFunction: """Constructs and returns the Lambda function. @@ -618,6 +653,7 @@ def _construct_lambda_function(self, intrinsics_resolver: IntrinsicsResolver) -> lambda_function.RuntimeManagementConfig = self.RuntimeManagementConfig # type: ignore[attr-defined] lambda_function.LoggingConfig = self.LoggingConfig + lambda_function.TenancyConfig = self.TenancyConfig lambda_function.RecursiveLoop = self.RecursiveLoop self._validate_package_type(lambda_function) return lambda_function diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index edd3ebe1ab..341c67fc54 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -56,6 +56,7 @@ class Globals: "LoggingConfig", "RecursiveLoop", "SourceKMSKeyArn", + "TenancyConfig", ], # Everything except # DefinitionBody: because its hard to reason about merge of Swagger dictionaries @@ -101,7 +102,12 @@ class Globals: } # unreleased_properties *must be* part of supported_properties too unreleased_properties: Dict[str, List[str]] = { - SamResourceType.Function.value: ["RuntimeManagementConfig", "RecursiveLoop", "SourceKMSKeyArn"], + SamResourceType.Function.value: [ + "RuntimeManagementConfig", + "RecursiveLoop", + "SourceKMSKeyArn", + "TenancyConfig", + ], } def __init__(self, template: Dict[str, Any]) -> None: diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 86e03b6f0c..330a678439 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -278502,6 +278502,9 @@ "title": "Tags", "type": "object" }, + "TenancyConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Timeout": { "allOf": [ { @@ -278899,6 +278902,9 @@ "title": "Tags", "type": "object" }, + "TenancyConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Timeout": { "allOf": [ { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 4b8b2cde01..4f2a396080 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -5609,6 +5609,9 @@ "title": "Tags", "type": "object" }, + "TenancyConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Timeout": { "allOf": [ { @@ -6197,6 +6200,9 @@ "title": "Tags", "type": "object" }, + "TenancyConfig": { + "$ref": "#/definitions/PassThroughProp" + }, "Timeout": { "allOf": [ { diff --git a/tests/translator/input/error_tenancy_with_dynamodb_event.yaml b/tests/translator/input/error_tenancy_with_dynamodb_event.yaml new file mode 100644 index 0000000000..46d8add3b3 --- /dev/null +++ b/tests/translator/input/error_tenancy_with_dynamodb_event.yaml @@ -0,0 +1,32 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyTable: + Type: AWS::DynamoDB::Table + Properties: + AttributeDefinitions: + - AttributeName: id + AttributeType: S + KeySchema: + - AttributeName: id + KeyType: HASH + BillingMode: PAY_PER_REQUEST + StreamSpecification: + StreamViewType: NEW_AND_OLD_IMAGES + + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + Events: + MyDynamoDBEvent: + Type: DynamoDB + Properties: + Stream: !GetAtt MyTable.StreamArn + StartingPosition: LATEST diff --git a/tests/translator/input/error_tenancy_with_function_url.yaml b/tests/translator/input/error_tenancy_with_function_url.yaml new file mode 100644 index 0000000000..9eca91d277 --- /dev/null +++ b/tests/translator/input/error_tenancy_with_function_url.yaml @@ -0,0 +1,15 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + FunctionUrlConfig: + AuthType: AWS_IAM diff --git a/tests/translator/input/error_tenancy_with_provisioned_concurrency.yaml b/tests/translator/input/error_tenancy_with_provisioned_concurrency.yaml new file mode 100644 index 0000000000..e20056b6ff --- /dev/null +++ b/tests/translator/input/error_tenancy_with_provisioned_concurrency.yaml @@ -0,0 +1,16 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + AutoPublishAlias: live + ProvisionedConcurrencyConfig: + ProvisionedConcurrentExecutions: 5 diff --git a/tests/translator/input/error_tenancy_with_snapstart.yaml b/tests/translator/input/error_tenancy_with_snapstart.yaml new file mode 100644 index 0000000000..d8e8cdcb19 --- /dev/null +++ b/tests/translator/input/error_tenancy_with_snapstart.yaml @@ -0,0 +1,15 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + SnapStart: + ApplyOn: PublishedVersions diff --git a/tests/translator/input/error_tenancy_with_sns_event.yaml b/tests/translator/input/error_tenancy_with_sns_event.yaml new file mode 100644 index 0000000000..731569e328 --- /dev/null +++ b/tests/translator/input/error_tenancy_with_sns_event.yaml @@ -0,0 +1,21 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyTopic: + Type: AWS::SNS::Topic + + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + Events: + MySNSEvent: + Type: SNS + Properties: + Topic: !Ref MyTopic diff --git a/tests/translator/input/error_tenancy_with_sqs_event.yaml b/tests/translator/input/error_tenancy_with_sqs_event.yaml new file mode 100644 index 0000000000..355736a5ca --- /dev/null +++ b/tests/translator/input/error_tenancy_with_sqs_event.yaml @@ -0,0 +1,21 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyQueue: + Type: AWS::SQS::Queue + + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {} + TenancyConfig: + TenantIsolationMode: PER_TENANT + Events: + MySQSEvent: + Type: SQS + Properties: + Queue: !GetAtt MyQueue.Arn diff --git a/tests/translator/input/function_with_tenancy_and_api_event.yaml b/tests/translator/input/function_with_tenancy_and_api_event.yaml new file mode 100644 index 0000000000..f82c9fb71a --- /dev/null +++ b/tests/translator/input/function_with_tenancy_and_api_event.yaml @@ -0,0 +1,19 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {'statusCode': 200, 'body': 'Hello'} + TenancyConfig: + TenantIsolationMode: PER_TENANT + Events: + MyApiEvent: + Type: Api + Properties: + Path: /hello + Method: get diff --git a/tests/translator/input/function_with_tenancy_and_httpapi_event.yaml b/tests/translator/input/function_with_tenancy_and_httpapi_event.yaml new file mode 100644 index 0000000000..6407f37e6c --- /dev/null +++ b/tests/translator/input/function_with_tenancy_and_httpapi_event.yaml @@ -0,0 +1,19 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.11 + Handler: index.handler + InlineCode: | + def handler(event, context): + return {'statusCode': 200, 'body': 'Hello'} + TenancyConfig: + TenantIsolationMode: PER_TENANT + Events: + MyHttpApiEvent: + Type: HttpApi + Properties: + Path: /hello + Method: get diff --git a/tests/translator/input/function_with_tenancy_config.yaml b/tests/translator/input/function_with_tenancy_config.yaml new file mode 100644 index 0000000000..2605a500b3 --- /dev/null +++ b/tests/translator/input/function_with_tenancy_config.yaml @@ -0,0 +1,11 @@ +Transform: AWS::Serverless-2016-10-31 + +Resources: + FunctionWithTenancyConfig: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python3.11 + TenancyConfig: + TenantIsolationMode: PER_TENANT diff --git a/tests/translator/input/function_with_tenancy_config_global.yaml b/tests/translator/input/function_with_tenancy_config_global.yaml new file mode 100644 index 0000000000..e962c6d26f --- /dev/null +++ b/tests/translator/input/function_with_tenancy_config_global.yaml @@ -0,0 +1,18 @@ +Globals: + Function: + Runtime: python3.8 + Handler: hello.handler + TenancyConfig: + TenantIsolationMode: PER_TENANT + +Resources: + MinimalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + + FunctionWithOverride: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/world.zip + Runtime: nodejs18.x diff --git a/tests/translator/output/aws-cn/function_with_tenancy_and_api_event.json b/tests/translator/output/aws-cn/function_with_tenancy_and_api_event.json new file mode 100644 index 0000000000..c685847e66 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_tenancy_and_api_event.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyApiEventPermissionProd": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessRestApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessRestApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ServerlessRestApiDeployment5cbed9eb47": { + "Properties": { + "Description": "RestApi deployment id: 5cbed9eb470e4da861c9f37642669fe49ac6de08", + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ServerlessRestApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment5cbed9eb47" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_tenancy_and_httpapi_event.json b/tests/translator/output/aws-cn/function_with_tenancy_and_httpapi_event.json new file mode 100644 index 0000000000..fcc031050a --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_tenancy_and_httpapi_event.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyHttpApiEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessHttpApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "openapi": "3.0.1", + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_tenancy_config.json b/tests/translator/output/aws-cn/function_with_tenancy_config.json new file mode 100644 index 0000000000..75f0e05174 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_tenancy_config.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "FunctionWithTenancyConfig": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithTenancyConfigRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithTenancyConfigRole": { + "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_tenancy_config_global.json b/tests/translator/output/aws-cn/function_with_tenancy_config_global.json new file mode 100644 index 0000000000..cf18d74809 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_tenancy_config_global.json @@ -0,0 +1,116 @@ +{ + "Resources": { + "FunctionWithOverride": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "world.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithOverrideRole": { + "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" + }, + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "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" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_tenancy_and_api_event.json b/tests/translator/output/aws-us-gov/function_with_tenancy_and_api_event.json new file mode 100644 index 0000000000..86aeeaca7f --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_tenancy_and_api_event.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyApiEventPermissionProd": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessRestApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessRestApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ServerlessRestApiDeployment41f4d38e59": { + "Properties": { + "Description": "RestApi deployment id: 41f4d38e591445f4e00f2a02eeb3f6ea34c41480", + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ServerlessRestApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment41f4d38e59" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_tenancy_and_httpapi_event.json b/tests/translator/output/aws-us-gov/function_with_tenancy_and_httpapi_event.json new file mode 100644 index 0000000000..570cd45695 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_tenancy_and_httpapi_event.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyHttpApiEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessHttpApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "openapi": "3.0.1", + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_tenancy_config.json b/tests/translator/output/aws-us-gov/function_with_tenancy_config.json new file mode 100644 index 0000000000..c418dc524a --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_tenancy_config.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "FunctionWithTenancyConfig": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithTenancyConfigRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithTenancyConfigRole": { + "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_tenancy_config_global.json b/tests/translator/output/aws-us-gov/function_with_tenancy_config_global.json new file mode 100644 index 0000000000..8253d42b96 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_tenancy_config_global.json @@ -0,0 +1,116 @@ +{ + "Resources": { + "FunctionWithOverride": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "world.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithOverrideRole": { + "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" + }, + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "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" + } + } +} diff --git a/tests/translator/output/error_tenancy_with_dynamodb_event.json b/tests/translator/output/error_tenancy_with_dynamodb_event.json new file mode 100644 index 0000000000..8e1aeb1572 --- /dev/null +++ b/tests/translator/output/error_tenancy_with_dynamodb_event.json @@ -0,0 +1,10 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "Event source 'DynamoDB' is not supported for functions enabled with tenancy configuration. ", + "Only Api and HttpApi event sources are supported." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. Event source 'DynamoDB' is not supported for functions enabled with tenancy configuration. Only Api and HttpApi event sources are supported." +} diff --git a/tests/translator/output/error_tenancy_with_function_url.json b/tests/translator/output/error_tenancy_with_function_url.json new file mode 100644 index 0000000000..735282d3fb --- /dev/null +++ b/tests/translator/output/error_tenancy_with_function_url.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "Function URL is not supported for functions enabled with tenancy configuration." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. Function URL is not supported for functions enabled with tenancy configuration." +} diff --git a/tests/translator/output/error_tenancy_with_provisioned_concurrency.json b/tests/translator/output/error_tenancy_with_provisioned_concurrency.json new file mode 100644 index 0000000000..e8cf0efa25 --- /dev/null +++ b/tests/translator/output/error_tenancy_with_provisioned_concurrency.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "Provisioned concurrency is not supported for functions enabled with tenancy configuration." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. Provisioned concurrency is not supported for functions enabled with tenancy configuration." +} diff --git a/tests/translator/output/error_tenancy_with_snapstart.json b/tests/translator/output/error_tenancy_with_snapstart.json new file mode 100644 index 0000000000..33032ec634 --- /dev/null +++ b/tests/translator/output/error_tenancy_with_snapstart.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "SnapStart is not supported for functions enabled with tenancy configuration." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. SnapStart is not supported for functions enabled with tenancy configuration." +} diff --git a/tests/translator/output/error_tenancy_with_sns_event.json b/tests/translator/output/error_tenancy_with_sns_event.json new file mode 100644 index 0000000000..c68fcbcb8b --- /dev/null +++ b/tests/translator/output/error_tenancy_with_sns_event.json @@ -0,0 +1,10 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "Event source 'SNS' is not supported for functions enabled with tenancy configuration. ", + "Only Api and HttpApi event sources are supported." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. Event source 'SNS' is not supported for functions enabled with tenancy configuration. Only Api and HttpApi event sources are supported." +} diff --git a/tests/translator/output/error_tenancy_with_sqs_event.json b/tests/translator/output/error_tenancy_with_sqs_event.json new file mode 100644 index 0000000000..b062bcd981 --- /dev/null +++ b/tests/translator/output/error_tenancy_with_sqs_event.json @@ -0,0 +1,10 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [MyFunction] is invalid. ", + "Event source 'SQS' is not supported for functions enabled with tenancy configuration. ", + "Only Api and HttpApi event sources are supported." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. Event source 'SQS' is not supported for functions enabled with tenancy configuration. Only Api and HttpApi event sources are supported." +} diff --git a/tests/translator/output/function_with_tenancy_and_api_event.json b/tests/translator/output/function_with_tenancy_and_api_event.json new file mode 100644 index 0000000000..6fed7c899a --- /dev/null +++ b/tests/translator/output/function_with_tenancy_and_api_event.json @@ -0,0 +1,130 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyApiEventPermissionProd": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessRestApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessRestApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "swagger": "2.0" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ServerlessRestApiDeployment5c4e8a6a13": { + "Properties": { + "Description": "RestApi deployment id: 5c4e8a6a1322dd51f1bb880a3926ffdbc929ad66", + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ServerlessRestApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment5c4e8a6a13" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/function_with_tenancy_and_httpapi_event.json b/tests/translator/output/function_with_tenancy_and_httpapi_event.json new file mode 100644 index 0000000000..5317386974 --- /dev/null +++ b/tests/translator/output/function_with_tenancy_and_httpapi_event.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello'}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionMyHttpApiEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "MyFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello", + { + "__ApiId__": { + "Ref": "ServerlessHttpApi" + }, + "__Stage__": "*" + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyFunctionRole": { + "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" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "openapi": "3.0.1", + "paths": { + "/hello": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/function_with_tenancy_config.json b/tests/translator/output/function_with_tenancy_config.json new file mode 100644 index 0000000000..f8463ac449 --- /dev/null +++ b/tests/translator/output/function_with_tenancy_config.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "FunctionWithTenancyConfig": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithTenancyConfigRole", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithTenancyConfigRole": { + "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_tenancy_config_global.json b/tests/translator/output/function_with_tenancy_config_global.json new file mode 100644 index 0000000000..b86fa79313 --- /dev/null +++ b/tests/translator/output/function_with_tenancy_config_global.json @@ -0,0 +1,116 @@ +{ + "Resources": { + "FunctionWithOverride": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "world.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "FunctionWithOverrideRole": { + "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" + }, + "MinimalFunction": { + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "TenancyConfig": { + "TenantIsolationMode": "PER_TENANT" + } + }, + "Type": "AWS::Lambda::Function" + }, + "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" + } + } +}