diff --git a/integration/combination/test_custom_http_api_domains_test.py b/integration/combination/test_custom_http_api_domains_test.py index 8711ba83bf..b51cbdf718 100644 --- a/integration/combination/test_custom_http_api_domains_test.py +++ b/integration/combination/test_custom_http_api_domains_test.py @@ -1,7 +1,11 @@ from unittest.case import skipIf from integration.config.service_names import CUSTOM_DOMAIN -from integration.helpers.base_internal_test import CUSTOM_DOMAIN_TOP_LEVEL, BaseInternalTest +from integration.helpers.base_internal_test import ( + CUSTOM_DOMAIN_TOP_LEVEL, + FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL, + BaseInternalTest, +) from integration.helpers.base_test import nonblocking from integration.helpers.resource import current_region_not_included @@ -24,7 +28,9 @@ def test_custom_http_api_domains_regional(self): result = api_gateway_client.get_domain_name(DomainName=domain_name_id) if "FeatureToggle" in self.pipeline_prefix: - self.assertEqual("httpapi.ftl.sam-gamma-regional.com", result["DomainName"]) + self.assertEqual( + f"httpapi-sam-gamma-regional.{FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL}", result["DomainName"] + ) else: self.assertEqual(f"httpapi-sam-gamma-regional.{CUSTOM_DOMAIN_TOP_LEVEL}", result["DomainName"]) diff --git a/integration/combination/test_custom_rest_api_domains.py b/integration/combination/test_custom_rest_api_domains.py index e931f7245a..45f558536a 100644 --- a/integration/combination/test_custom_rest_api_domains.py +++ b/integration/combination/test_custom_rest_api_domains.py @@ -1,7 +1,11 @@ from unittest.case import skipIf from integration.config.service_names import CUSTOM_DOMAIN -from integration.helpers.base_internal_test import CUSTOM_DOMAIN_TOP_LEVEL, BaseInternalTest +from integration.helpers.base_internal_test import ( + CUSTOM_DOMAIN_TOP_LEVEL, + FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL, + BaseInternalTest, +) from integration.helpers.base_test import nonblocking from integration.helpers.resource import current_region_not_included @@ -23,7 +27,7 @@ def test_custom_rest_api_domains_edge(self): result = api_gateway_client.get_domain_name(domainName=domain_name_id) if "FeatureToggle" in self.pipeline_prefix: - self.assertEqual("ftl.sam-gamma-edge.com", result["domainName"]) + self.assertEqual(f"sam-gamma-edge.{FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL}", result["domainName"]) else: self.assertEqual(f"sam-gamma-edge.{CUSTOM_DOMAIN_TOP_LEVEL}", result["domainName"]) @@ -44,7 +48,7 @@ def test_custom_rest_api_domains_regional(self): result = api_gateway_client.get_domain_name(domainName=domain_name_id) if "FeatureToggle" in self.pipeline_prefix: - self.assertEqual("ftl.sam-gamma-regional.com", result["domainName"]) + self.assertEqual(f"sam-gamma-regional.{FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL}", result["domainName"]) else: self.assertEqual(f"sam-gamma-regional.{CUSTOM_DOMAIN_TOP_LEVEL}", result["domainName"]) diff --git a/integration/combination/test_websocket_api_basic.py b/integration/combination/test_websocket_api_basic.py new file mode 100644 index 0000000000..66e4a39c00 --- /dev/null +++ b/integration/combination/test_websocket_api_basic.py @@ -0,0 +1,58 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiBasic(BaseTest): + + def test_websocket_api_basic(self): + """ + Creates a Basic WebSocket API + """ + # Validates list of generated resources is same as expected + self.create_and_verify_stack("combination/websocket_api_basic") + + stages = self.get_api_v2_stack_stages() + + self.assertEqual(len(stages), 1) + self.assertEqual(stages[0]["StageName"], "default") + + api_id = self.get_stack_outputs()["ApiId"] + api_2_client = self.client_provider.api_v2_client + + routes = api_2_client.get_routes(ApiId=api_id)["Items"] + self.assertEqual(len(routes), 1) + self.assertEqual(routes[0]["RouteKey"], "$default") + + integrations = api_2_client.get_integrations(ApiId=api_id)["Items"] + self.assertEqual(len(integrations), 1) + + def test_websocket_api_basic_config(self): + """ + Checks API config parameters that are strings + """ + self.create_and_verify_stack("combination/websocket_api_basic_config") + websocket_api_list = self.get_stack_resources("AWS::ApiGatewayV2::Api") + self.assertEqual(len(websocket_api_list), 1) + + websocket_resource = websocket_api_list[0] + websocket_api_id = websocket_resource["PhysicalResourceId"] + api_v2_client = self.client_provider.api_v2_client + api_configuration = api_v2_client.get_api(ApiId=websocket_api_id) + properties_to_check = { + "ApiKeySelectionExpression": "$request.header.x-api-key", + "Description": "Toy API", + "DisableExecuteApiEndpoint": False, + "Name": "MyApiName", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + } + for key, value in properties_to_check.items(): + self.assertEqual(api_configuration[key], value) + # assert custom tags are present + # CFN and SAM tags also exist, so we can't check equality of the full list + self.assertEqual(api_configuration["Tags"].get("t1"), "v1") + self.assertEqual(api_configuration["Tags"].get("t2"), "v2") diff --git a/integration/combination/test_websocket_api_custom_domains.py b/integration/combination/test_websocket_api_custom_domains.py new file mode 100644 index 0000000000..9e149c85fa --- /dev/null +++ b/integration/combination/test_websocket_api_custom_domains.py @@ -0,0 +1,47 @@ +from unittest.case import skipIf + +from integration.config.service_names import CUSTOM_DOMAIN, WEBSOCKET_API +from integration.helpers.base_internal_test import ( + CUSTOM_DOMAIN_TOP_LEVEL, + FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL, + BaseInternalTest, +) +from integration.helpers.base_test import nonblocking +from integration.helpers.resource import current_region_does_not_support, current_region_not_included + + +# Custom domain tests require pre-created infrastructure (hosted zones, certificates) +# that only exists in us-east-1. +@skipIf( + current_region_does_not_support([WEBSOCKET_API]) or current_region_not_included([CUSTOM_DOMAIN]), + "WebSocketApi is not supported or CustomDomain infrastructure is not available in this testing region", +) +@nonblocking +class TestWebSocketApiCustomDomains(BaseInternalTest): + def test_websocket_custom_api_domains_regional(self): + self.create_and_verify_stack("combination/websocket_api_custom_domains_regional") + + domain_name_list = self.get_stack_resources("AWS::ApiGatewayV2::DomainName") + self.assertEqual(1, len(domain_name_list)) + + domain_name_id = self.get_physical_id_by_type("AWS::ApiGatewayV2::DomainName") + + api_gateway_client = self.client_provider.api_v2_client + result = api_gateway_client.get_domain_name(DomainName=domain_name_id) + + if "FeatureToggle" in self.pipeline_prefix: + self.assertEqual( + f"websocket-sam-gamma-regional.{FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL}", result["DomainName"] + ) + else: + self.assertEqual(f"websocket-sam-gamma-regional.{CUSTOM_DOMAIN_TOP_LEVEL}", result["DomainName"]) + + domain_name_configs = result["DomainNameConfigurations"] + self.assertEqual(1, len(domain_name_configs)) + domain_name_config = domain_name_configs[0] + + self.assertEqual("REGIONAL", domain_name_config["EndpointType"]) + self.assertEqual("TLS_1_2", domain_name_config["SecurityPolicy"]) + + domain_name_configs = result["DomainNameConfigurations"] + self.assertEqual(1, len(domain_name_configs)) diff --git a/integration/combination/test_websocket_api_multiple.py b/integration/combination/test_websocket_api_multiple.py new file mode 100644 index 0000000000..f0e56b643d --- /dev/null +++ b/integration/combination/test_websocket_api_multiple.py @@ -0,0 +1,15 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiMultiple(BaseTest): + + def test_websocket_multi_api(self): + self.create_and_verify_stack("combination/websocket_api_multiple_api") + + def test_websocket_multi_route(self): + self.create_and_verify_stack("combination/websocket_api_multiple_routes") diff --git a/integration/combination/test_websocket_api_route_config.py b/integration/combination/test_websocket_api_route_config.py new file mode 100644 index 0000000000..b3c83dc3dd --- /dev/null +++ b/integration/combination/test_websocket_api_route_config.py @@ -0,0 +1,35 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiRouteConfig(BaseTest): + + def test_websocket_api_route_config(self): + """ + Checks API config parameters that are strings + """ + self.create_and_verify_stack("combination/websocket_api_route_config") + websocket_route_list = self.get_stack_resources("AWS::ApiGatewayV2::Route") + self.assertEqual(len(websocket_route_list), 1) + websocket_route_integ_list = self.get_stack_resources("AWS::ApiGatewayV2::Integration") + self.assertEqual(len(websocket_route_integ_list), 1) + websocket_route_perm_list = self.get_stack_resources("AWS::Lambda::Permission") + self.assertEqual(len(websocket_route_perm_list), 1) + api_id = self.get_stack_outputs()["ApiId"] + api_2_client = self.client_provider.api_v2_client + routes = api_2_client.get_routes(ApiId=api_id)["Items"] + self.assertEqual(len(routes), 1) + route = routes[0] + self.assertEqual(route["RouteKey"], "$connect") + self.assertEqual(route["ModelSelectionExpression"], "$request.body.modelType") + self.assertEqual(route["OperationName"], "connect") + self.assertIsNotNone(route["RequestParameters"].get("route.request.querystring.p1")) + self.assertEqual(route["RouteResponseSelectionExpression"], "$default") + integrations = api_2_client.get_integrations(ApiId=api_id) + self.assertEqual(len(integrations["Items"]), 1) + integration = integrations["Items"][0] + self.assertEqual(integration["TimeoutInMillis"], 15000) diff --git a/integration/combination/test_websocket_api_route_settings.py b/integration/combination/test_websocket_api_route_settings.py new file mode 100644 index 0000000000..894d476a3a --- /dev/null +++ b/integration/combination/test_websocket_api_route_settings.py @@ -0,0 +1,20 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiRouteSettings(BaseTest): + def test_websocket_api_route_settings(self): + """ + Verifies that RouteSettings with specific route keys deploys successfully. + This test ensures Stage has DependsOn for routes. + """ + self.create_and_verify_stack("combination/websocket_api_route_settings") + + stages = self.get_api_v2_stack_stages() + self.assertEqual(len(stages), 1) + stage = stages[0] + self.assertIsNotNone(stage.get("RouteSettings")) diff --git a/integration/combination/test_websocket_api_stage_config.py b/integration/combination/test_websocket_api_stage_config.py new file mode 100644 index 0000000000..d12656f37f --- /dev/null +++ b/integration/combination/test_websocket_api_stage_config.py @@ -0,0 +1,22 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiStageConfig(BaseTest): + + def test_websocket_api_stage_config(self): + """ + Checks API config parameters that are strings + """ + self.create_and_verify_stack("combination/websocket_api_stage_config") + stages = self.get_api_v2_stack_stages() + self.assertEqual(len(stages), 1) + stage = stages[0] + self.assertEqual(stage["StageName"], "Prod") + self.assertEqual(stage["StageVariables"], {"var1": "val1", "var2": "val2"}) + self.assertIsNotNone(stage["Tags"].get("t1")) + self.assertIsNotNone(stage["Tags"].get("t2")) diff --git a/integration/combination/test_websocket_api_with_auth.py b/integration/combination/test_websocket_api_with_auth.py new file mode 100644 index 0000000000..d62210cc97 --- /dev/null +++ b/integration/combination/test_websocket_api_with_auth.py @@ -0,0 +1,76 @@ +from unittest.case import skipIf + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiWithAuth(BaseTest): + + def test_websocket_api_with_iam_auth(self): + """ + Creates a WebSocket API with an IAM authorizer + """ + self.create_and_verify_stack("combination/websocket_api_with_iam_auth") + + websocket_api_list = self.get_stack_resources("AWS::ApiGatewayV2::Api") + self.assertEqual(len(websocket_api_list), 1) + + stages = self.get_api_v2_stack_stages() + + self.assertEqual(len(stages), 1) + self.assertEqual(stages[0]["StageName"], "default") + + websocket_resource = websocket_api_list[0] + websocket_api_id = websocket_resource["PhysicalResourceId"] + api_v2_client = self.client_provider.api_v2_client + routes_list = api_v2_client.get_routes(ApiId=websocket_api_id)["Items"] + route = routes_list[0] + self.assertEqual(route["AuthorizationType"], "AWS_IAM") + + def test_none_auth(self): + self.create_and_verify_stack("combination/websocket_api_with_none_auth") + + websocket_api_list = self.get_stack_resources("AWS::ApiGatewayV2::Api") + self.assertEqual(len(websocket_api_list), 1) + + websocket_resource = websocket_api_list[0] + websocket_api_id = websocket_resource["PhysicalResourceId"] + api_v2_client = self.client_provider.api_v2_client + routes_list = api_v2_client.get_routes(ApiId=websocket_api_id)["Items"] + route = routes_list[0] + self.assertEqual(route["AuthorizationType"], "NONE") + + def test_websocket_api_with_lambda_auth_config(self): + """ + Creates a WebSocket API with a Lambda authorizer + """ + self.create_and_verify_stack("combination/websocket_api_with_lambda_auth") + + websocket_api_list = self.get_stack_resources("AWS::ApiGatewayV2::Api") + self.assertEqual(len(websocket_api_list), 1) + + websocket_resource = websocket_api_list[0] + websocket_api_id = websocket_resource["PhysicalResourceId"] + api_v2_client = self.client_provider.api_v2_client + + route_list = api_v2_client.get_routes(ApiId=websocket_api_id)["Items"] + self.assertEqual(len(route_list), 1) + route = route_list[0] + self.assertEqual(route["AuthorizationType"], "CUSTOM") + self.assertIsNotNone(route["AuthorizerId"]) + + authorizer_list = api_v2_client.get_authorizers(ApiId=websocket_api_id)["Items"] + self.assertEqual(len(authorizer_list), 1) + lambda_auth = authorizer_list[0] + # Not sure this is returning properly either + self.assertEqual(lambda_auth["AuthorizerType"], "REQUEST") + # Verify authorizer URI contains expected components + authorizer_uri = lambda_auth["AuthorizerUri"] + self.assertIn("lambda:path/2015-03-31/functions", authorizer_uri) + self.assertIn("MyAuthFn", authorizer_uri) + self.assertIn("/invocations", authorizer_uri) + + # Same authorizer coming from the route and from the authorizers + self.assertEqual(route["AuthorizerId"], lambda_auth["AuthorizerId"]) diff --git a/integration/combination/test_websocket_api_with_disable_execute_api_endpoint.py b/integration/combination/test_websocket_api_with_disable_execute_api_endpoint.py new file mode 100644 index 0000000000..d139e9272a --- /dev/null +++ b/integration/combination/test_websocket_api_with_disable_execute_api_endpoint.py @@ -0,0 +1,27 @@ +from unittest.case import skipIf + +from parameterized import parameterized + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiWithDisableExecuteApiEndpoint(BaseTest): + @parameterized.expand([True, False]) + def test_disable_execute_api_endpoint_true(self, is_disable): + parameters = [ + { + "ParameterKey": "DisableExecuteApiEndpointValue", + "ParameterValue": "true" if is_disable else "false", + "UsePreviousValue": False, + "ResolvedValue": "string", + } + ] + + self.create_and_verify_stack("combination/websocket_api_with_disable_execute_api_endpoint", parameters) + api_2_client = self.client_provider.api_v2_client + api_id = self.get_stack_outputs()["ApiId"] + api_result = api_2_client.get_api(ApiId=api_id) + self.assertEqual(api_result["DisableExecuteApiEndpoint"], is_disable) diff --git a/integration/combination/test_websocket_api_with_disable_schema_validation.py b/integration/combination/test_websocket_api_with_disable_schema_validation.py new file mode 100644 index 0000000000..cbb89350df --- /dev/null +++ b/integration/combination/test_websocket_api_with_disable_schema_validation.py @@ -0,0 +1,27 @@ +from unittest.case import skipIf + +from parameterized import parameterized + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketApiDisableSchemaValidation(BaseTest): + @parameterized.expand([True, False]) + def test_disable_schema_validation(self, is_disable): + parameters = [ + { + "ParameterKey": "DisableSchemaValidationValue", + "ParameterValue": "true" if is_disable else "false", + "UsePreviousValue": False, + "ResolvedValue": "string", + } + ] + self.create_and_verify_stack("combination/websocket_api_with_disable_schema_validation", parameters) + websocket_api_list = self.get_stack_resources("AWS::ApiGatewayV2::Api") + self.assertEqual(len(websocket_api_list), 1) + # API Gateway SDK for some reason doesn't return the disableSchemaValidation + # property when getting the API, so we just check that there were no errors + # during the creation, but we can't check that it was properly applied diff --git a/integration/combination/test_websocket_api_with_ip_address_type.py b/integration/combination/test_websocket_api_with_ip_address_type.py new file mode 100644 index 0000000000..2193f6948e --- /dev/null +++ b/integration/combination/test_websocket_api_with_ip_address_type.py @@ -0,0 +1,29 @@ +from unittest.case import skipIf + +from parameterized import parameterized + +from integration.config.service_names import WEBSOCKET_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([WEBSOCKET_API]), "WebSocketApi is not supported in this region") +class TestWebSocketIpAddress(BaseTest): + @parameterized.expand( + [ + ("ipv4",), + ("dualstack",), + ] + ) + def test_ip_address(self, ip_type): + parameters = [ + { + "ParameterKey": "IpAddressType", + "ParameterValue": ip_type, + } + ] + self.create_and_verify_stack("combination/websocket_api_with_ip_address_type", parameters) + api_2_client = self.client_provider.api_v2_client + api_id = self.get_stack_outputs()["ApiId"] + api_result = api_2_client.get_api(ApiId=api_id) + self.assertEqual(api_result["IpAddressType"], ip_type) diff --git a/integration/config/region_service_inclusion.yaml b/integration/config/region_service_inclusion.yaml new file mode 100644 index 0000000000..78f2144471 --- /dev/null +++ b/integration/config/region_service_inclusion.yaml @@ -0,0 +1,5 @@ +regions: + us-east-1: + - CustomDomain +Metadata: + SamTransformTest: true diff --git a/integration/config/service_names.py b/integration/config/service_names.py index 4de385e0ea..7177d4436a 100644 --- a/integration/config/service_names.py +++ b/integration/config/service_names.py @@ -5,6 +5,7 @@ LAYERS = "Layers" HTTP_API = "HttpApi" REST_API = "RestApi" +WEBSOCKET_API = "WebSocketApi" IOT = "IoT" CODE_DEPLOY = "CodeDeploy" LOCATION = "Location" diff --git a/integration/helpers/base_internal_test.py b/integration/helpers/base_internal_test.py index 0651ca21e5..a4bf5b0b65 100644 --- a/integration/helpers/base_internal_test.py +++ b/integration/helpers/base_internal_test.py @@ -5,6 +5,7 @@ from integration.helpers.base_test import BaseTest CUSTOM_DOMAIN_TOP_LEVEL = "tooling.lambda.aws.dev" +FEATURE_TOGGLE_CUSTOM_DOMAIN_TOP_LEVEL = "ftl.tooling.lambda.aws.dev" class BaseInternalTest(BaseTest): diff --git a/integration/resources/expected/combination/api_with_custom_domains_edge.json b/integration/resources/expected/combination/api_with_custom_domains_edge.json index 2fee6e3bce..6297241e1a 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_edge.json +++ b/integration/resources/expected/combination/api_with_custom_domains_edge.json @@ -1,6 +1,6 @@ [ { - "LogicalResourceId": "RecordSetGroup303b65d470", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -8,7 +8,7 @@ "ResourceType": "AWS::ApiGateway::Deployment" }, { - "LogicalResourceId": "ApiGatewayDomainNameed93f7bdb0", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/api_with_custom_domains_edge_feature_toggle.json b/integration/resources/expected/combination/api_with_custom_domains_edge_feature_toggle.json index 87c82b557f..6297241e1a 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_edge_feature_toggle.json +++ b/integration/resources/expected/combination/api_with_custom_domains_edge_feature_toggle.json @@ -1,6 +1,6 @@ [ { - "LogicalResourceId": "RecordSetGroupc911be5759", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -8,7 +8,7 @@ "ResourceType": "AWS::ApiGateway::Deployment" }, { - "LogicalResourceId": "ApiGatewayDomainName299fac327d", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/api_with_custom_domains_regional.json b/integration/resources/expected/combination/api_with_custom_domains_regional.json index bbb9962831..7610564c63 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_regional.json +++ b/integration/resources/expected/combination/api_with_custom_domains_regional.json @@ -16,7 +16,7 @@ "ResourceType": "AWS::ApiGateway::RestApi" }, { - "LogicalResourceId": "RecordSetGroup303b65d470", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGateway::BasePathMapping" }, { - "LogicalResourceId": "ApiGatewayDomainNamec65e226806", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/api_with_custom_domains_regional_feature_toggle.json b/integration/resources/expected/combination/api_with_custom_domains_regional_feature_toggle.json index 751a57f174..7610564c63 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_regional_feature_toggle.json +++ b/integration/resources/expected/combination/api_with_custom_domains_regional_feature_toggle.json @@ -16,7 +16,7 @@ "ResourceType": "AWS::ApiGateway::RestApi" }, { - "LogicalResourceId": "RecordSetGroupd17dced08c", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGateway::BasePathMapping" }, { - "LogicalResourceId": "ApiGatewayDomainName98c928338d", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification.json b/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification.json index a5bfc9ae74..7610564c63 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification.json +++ b/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification.json @@ -16,7 +16,7 @@ "ResourceType": "AWS::ApiGateway::RestApi" }, { - "LogicalResourceId": "RecordSetGroup303b65d470", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGateway::BasePathMapping" }, { - "LogicalResourceId": "ApiGatewayDomainName468109b572", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification_feature_toggle.json b/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification_feature_toggle.json index db2d7a0f56..7610564c63 100644 --- a/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification_feature_toggle.json +++ b/integration/resources/expected/combination/api_with_custom_domains_regional_ownership_verification_feature_toggle.json @@ -16,7 +16,7 @@ "ResourceType": "AWS::ApiGateway::RestApi" }, { - "LogicalResourceId": "RecordSetGroupd17dced08c", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGateway::BasePathMapping" }, { - "LogicalResourceId": "ApiGatewayDomainNamef593820b0b", + "LogicalResourceId": "ApiGatewayDomainName", "ResourceType": "AWS::ApiGateway::DomainName" }, { diff --git a/integration/resources/expected/combination/http_api_with_custom_domains_regional.json b/integration/resources/expected/combination/http_api_with_custom_domains_regional.json index a5f4eccc8c..ef8053ea4f 100644 --- a/integration/resources/expected/combination/http_api_with_custom_domains_regional.json +++ b/integration/resources/expected/combination/http_api_with_custom_domains_regional.json @@ -20,7 +20,7 @@ "ResourceType": "AWS::ApiGatewayV2::Api" }, { - "LogicalResourceId": "RecordSetGroup303b65d470", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGatewayV2::Stage" }, { - "LogicalResourceId": "ApiGatewayDomainNameV213a98a57a3", + "LogicalResourceId": "ApiGatewayDomainNameV2", "ResourceType": "AWS::ApiGatewayV2::DomainName" }, { diff --git a/integration/resources/expected/combination/http_api_with_custom_domains_regional_feature_toggle.json b/integration/resources/expected/combination/http_api_with_custom_domains_regional_feature_toggle.json index 79cd349153..ef8053ea4f 100644 --- a/integration/resources/expected/combination/http_api_with_custom_domains_regional_feature_toggle.json +++ b/integration/resources/expected/combination/http_api_with_custom_domains_regional_feature_toggle.json @@ -20,7 +20,7 @@ "ResourceType": "AWS::ApiGatewayV2::Api" }, { - "LogicalResourceId": "RecordSetGroupd17dced08c", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGatewayV2::Stage" }, { - "LogicalResourceId": "ApiGatewayDomainNameV26198c55d75", + "LogicalResourceId": "ApiGatewayDomainNameV2", "ResourceType": "AWS::ApiGatewayV2::DomainName" }, { diff --git a/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification.json b/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification.json index 614bb79b23..ef8053ea4f 100644 --- a/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification.json +++ b/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification.json @@ -20,7 +20,7 @@ "ResourceType": "AWS::ApiGatewayV2::Api" }, { - "LogicalResourceId": "RecordSetGroup303b65d470", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGatewayV2::Stage" }, { - "LogicalResourceId": "ApiGatewayDomainNameV23c498a5924", + "LogicalResourceId": "ApiGatewayDomainNameV2", "ResourceType": "AWS::ApiGatewayV2::DomainName" }, { diff --git a/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification_feature_toggle.json b/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification_feature_toggle.json index 790f04e469..ef8053ea4f 100644 --- a/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification_feature_toggle.json +++ b/integration/resources/expected/combination/http_api_with_custom_domains_regional_ownership_verification_feature_toggle.json @@ -20,7 +20,7 @@ "ResourceType": "AWS::ApiGatewayV2::Api" }, { - "LogicalResourceId": "RecordSetGroupd17dced08c", + "LogicalResourceId": "RecordSetGroup", "ResourceType": "AWS::Route53::RecordSetGroup" }, { @@ -28,7 +28,7 @@ "ResourceType": "AWS::ApiGatewayV2::Stage" }, { - "LogicalResourceId": "ApiGatewayDomainNameV2483cac8ea6", + "LogicalResourceId": "ApiGatewayDomainNameV2", "ResourceType": "AWS::ApiGatewayV2::DomainName" }, { diff --git a/integration/resources/expected/combination/websocket_api_basic.json b/integration/resources/expected/combination/websocket_api_basic.json new file mode 100644 index 0000000000..4f2de2ab74 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_basic.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "DefaultFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DefaultFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_basic_config.json b/integration/resources/expected/combination/websocket_api_basic_config.json new file mode 100644 index 0000000000..4f2de2ab74 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_basic_config.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "DefaultFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DefaultFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_custom_domains_regional.json b/integration/resources/expected/combination/websocket_api_custom_domains_regional.json new file mode 100644 index 0000000000..11819b2073 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_custom_domains_regional.json @@ -0,0 +1,46 @@ +[ + { + "LogicalResourceId": "ApiGatewayDomainNameV2", + "ResourceType": "AWS::ApiGatewayV2::DomainName" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiProdStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyApigetApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyApipostApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "RecordSetGroup", + "ResourceType": "AWS::Route53::RecordSetGroup" + } +] diff --git a/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification.json b/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification.json new file mode 100644 index 0000000000..e64717047b --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification.json @@ -0,0 +1,46 @@ +[ + { + "LogicalResourceId": "ApiGatewayDomainNameV2", + "ResourceType": "AWS::ApiGatewayV2::DomainName" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyApigetApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyApipostApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "RecordSetGroup", + "ResourceType": "AWS::Route53::RecordSetGroup" + } +] diff --git a/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification_feature_toggle.json b/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification_feature_toggle.json new file mode 100644 index 0000000000..e64717047b --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_custom_domains_regional_ownership_verification_feature_toggle.json @@ -0,0 +1,46 @@ +[ + { + "LogicalResourceId": "ApiGatewayDomainNameV2", + "ResourceType": "AWS::ApiGatewayV2::DomainName" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyApigetApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyApipostApiMapping", + "ResourceType": "AWS::ApiGatewayV2::ApiMapping" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "RecordSetGroup", + "ResourceType": "AWS::Route53::RecordSetGroup" + } +] diff --git a/integration/resources/expected/combination/websocket_api_multiple_api.json b/integration/resources/expected/combination/websocket_api_multiple_api.json new file mode 100644 index 0000000000..e7aaaad4f8 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_multiple_api.json @@ -0,0 +1,50 @@ +[ + { + "LogicalResourceId": "DefaultFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DefaultFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "Api1", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "Api1DefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "Api1DefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "Api1DefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "Api1DefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "Api2", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "Api2DefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "Api2DefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "Api2DefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "Api2DefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_multiple_routes.json b/integration/resources/expected/combination/websocket_api_multiple_routes.json new file mode 100644 index 0000000000..1379b61814 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_multiple_routes.json @@ -0,0 +1,102 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "DisconnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DisconnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "DefaultFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DefaultFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "SendFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "SendFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDisconnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDisconnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDisconnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiSendRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiSendIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiSendPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiNonsenseRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiNonsenseIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiNonsensePermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_route_config.json b/integration/resources/expected/combination/websocket_api_route_config.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_route_config.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_route_settings.json b/integration/resources/expected/combination/websocket_api_route_settings.json new file mode 100644 index 0000000000..b5b670da75 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_route_settings.json @@ -0,0 +1,42 @@ +[ + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyApiSendmessageIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiSendmessagePermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiSendmessageRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + } +] diff --git a/integration/resources/expected/combination/websocket_api_stage_config.json b/integration/resources/expected/combination/websocket_api_stage_config.json new file mode 100644 index 0000000000..73fa15bf2c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_stage_config.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "DefaultFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "DefaultFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiDefaultIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiDefaultPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiDefaultRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiProdStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_disable_execute_api_endpoint.json b/integration/resources/expected/combination/websocket_api_with_disable_execute_api_endpoint.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_disable_execute_api_endpoint.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_disable_schema_validation.json b/integration/resources/expected/combination/websocket_api_with_disable_schema_validation.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_disable_schema_validation.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_iam_auth.json b/integration/resources/expected/combination/websocket_api_with_iam_auth.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_iam_auth.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_ip_address_type.json b/integration/resources/expected/combination/websocket_api_with_ip_address_type.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_ip_address_type.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_lambda_auth.json b/integration/resources/expected/combination/websocket_api_with_lambda_auth.json new file mode 100644 index 0000000000..7d9330baf8 --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_lambda_auth.json @@ -0,0 +1,46 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyApiConnectAuthorizer", + "ResourceType": "AWS::ApiGatewayV2::Authorizer" + }, + { + "LogicalResourceId": "MyApiAuthorizerPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyAuthFnRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyAuthFn", + "ResourceType": "AWS::Lambda::Function" + } +] diff --git a/integration/resources/expected/combination/websocket_api_with_none_auth.json b/integration/resources/expected/combination/websocket_api_with_none_auth.json new file mode 100644 index 0000000000..560c05678c --- /dev/null +++ b/integration/resources/expected/combination/websocket_api_with_none_auth.json @@ -0,0 +1,30 @@ +[ + { + "LogicalResourceId": "ConnectFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "ConnectFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyApiConnectIntegration", + "ResourceType": "AWS::ApiGatewayV2::Integration" + }, + { + "LogicalResourceId": "MyApiConnectPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyApiConnectRoute", + "ResourceType": "AWS::ApiGatewayV2::Route" + }, + { + "LogicalResourceId": "MyApiDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/templates/combination/websocket_api_basic.yaml b/integration/resources/templates/combination/websocket_api_basic.yaml new file mode 100644 index 0000000000..a11de573dd --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_basic.yaml @@ -0,0 +1,20 @@ +Resources: + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_basic_config.yaml b/integration/resources/templates/combination/websocket_api_basic_config.yaml new file mode 100644 index 0000000000..99070c6ae7 --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_basic_config.yaml @@ -0,0 +1,27 @@ +Resources: + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + ApiKeySelectionExpression: $request.header.x-api-key + Description: Toy API + DisableExecuteApiEndpoint: false + DisableSchemaValidation: false + Name: MyApiName + RouteSelectionExpression: $request.body.action + Tags: + t1: v1 + t2: v2 + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml b/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml new file mode 100644 index 0000000000..56d8e91657 --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml @@ -0,0 +1,50 @@ +Parameters: + MyDomainName: + Type: String + MyDomainCert: + Type: String + HostedZoneId: + Type: String + +Globals: + WebSocketApi: + Domain: + DomainName: + Ref: MyDomainName + CertificateArn: + Ref: MyDomainCert + EndpointConfiguration: REGIONAL + SecurityPolicy: TLS_1_2 + BasePath: + - /get + - /post + Route53: + HostedZoneId: + Ref: HostedZoneId + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async(event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs24.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt MyFunction.Arn + StageName: Prod + +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_multiple_api.yaml b/integration/resources/templates/combination/websocket_api_multiple_api.yaml new file mode 100644 index 0000000000..456aaf736f --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_multiple_api.yaml @@ -0,0 +1,24 @@ +Resources: + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + Api1: + Type: AWS::Serverless::WebSocketApi + Properties: + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn + Api2: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: Api2 + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_multiple_routes.yaml b/integration/resources/templates/combination/websocket_api_multiple_routes.yaml new file mode 100644 index 0000000000..ab9237a811 --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_multiple_routes.yaml @@ -0,0 +1,42 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + DisconnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + SendFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + $disconnect: + FunctionArn: !GetAtt DisconnectFunction.Arn + $default: + FunctionArn: !GetAtt DefaultFunction.Arn + send: + FunctionArn: !GetAtt SendFunction.Arn + nonsense: + FunctionArn: !GetAtt DefaultFunction.Arn +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_route_config.yaml b/integration/resources/templates/combination/websocket_api_route_config.yaml new file mode 100644 index 0000000000..6dcfe7b9da --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_route_config.yaml @@ -0,0 +1,27 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Routes: + $connect: + ApiKeyRequired: false + FunctionArn: !GetAtt ConnectFunction.Arn + IntegrationTimeout: 15000 + ModelSelectionExpression: $request.body.modelType + OperationName: connect + RequestParameters: + route.request.querystring.p1: + Required: true + RouteResponseSelectionExpression: $default + RouteSelectionExpression: $request.body.action +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_route_settings.yaml b/integration/resources/templates/combination/websocket_api_route_settings.yaml new file mode 100644 index 0000000000..67e00782e7 --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_route_settings.yaml @@ -0,0 +1,27 @@ +Metadata: + SamTransformTest: true + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + RouteSelectionExpression: $request.body.action + RouteSettings: + sendMessage: + ThrottlingBurstLimit: 200 + Routes: + $default: + FunctionArn: !GetAtt MyFunction.Arn + sendMessage: + FunctionArn: !GetAtt MyFunction.Arn + +Outputs: + ApiId: + Value: !Ref MyApi diff --git a/integration/resources/templates/combination/websocket_api_stage_config.yaml b/integration/resources/templates/combination/websocket_api_stage_config.yaml new file mode 100644 index 0000000000..c43e97f50a --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_stage_config.yaml @@ -0,0 +1,28 @@ +Resources: + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + PropagateTags: true + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn + RouteSelectionExpression: $request.body.action + StageName: Prod + StageVariables: + var1: val1 + var2: val2 + Tags: + t1: val1 + t2: val2 +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml b/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml new file mode 100644 index 0000000000..2421e8f479 --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml @@ -0,0 +1,27 @@ +Parameters: + DisableExecuteApiEndpointValue: + Type: String + AllowedValues: ['true', 'false'] + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + DisableExecuteApiEndpoint: !Ref DisableExecuteApiEndpointValue + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml b/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml new file mode 100644 index 0000000000..118ea5434b --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml @@ -0,0 +1,27 @@ +Parameters: + DisableSchemaValidationValue: + Type: String + AllowedValues: ['true', 'false'] + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + InlineCode: | + print("hello") + Runtime: nodejs24.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + DisableSchemaValidation: true + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_iam_auth.yaml b/integration/resources/templates/combination/websocket_api_with_iam_auth.yaml new file mode 100644 index 0000000000..3348d7d4ac --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_iam_auth.yaml @@ -0,0 +1,19 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: AWS_IAM + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml b/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml new file mode 100644 index 0000000000..be226be46b --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml @@ -0,0 +1,26 @@ +Parameters: + IpAddressType: + Type: String + AllowedValues: [ipv4, dualstack] + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + IpAddressType: !Ref IpAddressType + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_lambda_auth.yaml b/integration/resources/templates/combination/websocket_api_with_lambda_auth.yaml new file mode 100644 index 0000000000..bb52f0a23f --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_lambda_auth.yaml @@ -0,0 +1,28 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + print("hello") + Handler: hello.handler + Runtime: nodejs24.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + AuthArn: !GetAtt MyAuthFn.Arn + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + MyAuthFn: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + print("hello") + Handler: authorizer.handler + Runtime: nodejs24.x +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/combination/websocket_api_with_none_auth.yaml b/integration/resources/templates/combination/websocket_api_with_none_auth.yaml new file mode 100644 index 0000000000..ee6c2f626c --- /dev/null +++ b/integration/resources/templates/combination/websocket_api_with_none_auth.yaml @@ -0,0 +1,22 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs24.x + CodeUri: ${codeuri} + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: NONE + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn +Outputs: + ApiId: + Value: !Ref MyApi +Metadata: + SamTransformTest: true diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index 556d08722c..433ac92a77 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.108.0" +__version__ = "1.109.0" diff --git a/samtranslator/internal/schema_source/aws_serverless_httpapi.py b/samtranslator/internal/schema_source/aws_serverless_httpapi.py index 7a659583cb..2f141265c8 100644 --- a/samtranslator/internal/schema_source/aws_serverless_httpapi.py +++ b/samtranslator/internal/schema_source/aws_serverless_httpapi.py @@ -10,7 +10,6 @@ ResourceAttributes, SamIntrinsicable, get_prop, - passthrough_prop, ) oauth2authorizer = get_prop("sam-property-httpapi-oauth2authorizer") @@ -19,8 +18,8 @@ auth = get_prop("sam-property-httpapi-httpapiauth") corsconfiguration = get_prop("sam-property-httpapi-httpapicorsconfiguration") definitionuri = get_prop("sam-property-httpapi-httpapidefinition") -route53 = get_prop("sam-property-httpapi-route53configuration") -domain = get_prop("sam-property-httpapi-httpapidomainconfiguration") +route53 = get_prop("sam-property-gatewayv2-route53configuration") +domain = get_prop("sam-property-gatewayv2-domainconfiguration") properties = get_prop("sam-resource-httpapi") @@ -78,16 +77,8 @@ class Route53(BaseModel): HostedZoneId: PassThroughProp | None = route53("HostedZoneId") HostedZoneName: PassThroughProp | None = route53("HostedZoneName") IpV6: bool | None = route53("IpV6") - SetIdentifier: PassThroughProp | None = passthrough_prop( - "sam-property-httpapi-route53configuration", - "SetIdentifier", - ["AWS::Route53::RecordSetGroup.RecordSet", "SetIdentifier"], - ) - Region: PassThroughProp | None = passthrough_prop( - "sam-property-httpapi-route53configuration", - "Region", - ["AWS::Route53::RecordSetGroup.RecordSet", "Region"], - ) + SetIdentifier: PassThroughProp | None = route53("SetIdentifier") + Region: PassThroughProp | None = route53("Region") class Domain(BaseModel): diff --git a/samtranslator/internal/schema_source/aws_serverless_websocketapi.py b/samtranslator/internal/schema_source/aws_serverless_websocketapi.py new file mode 100644 index 0000000000..291c99748e --- /dev/null +++ b/samtranslator/internal/schema_source/aws_serverless_websocketapi.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from typing import Literal + +from samtranslator.internal.schema_source.common import ( + BaseModel, + DictStrAny, + PassThroughProp, + ResourceAttributes, + SamIntrinsicable, + get_prop, +) + +# TODO add docs + +auth_spec = get_prop("sam-property-websocketapi-authconfiguration") +route_spec = get_prop("sam-property-websocketapi-routeconfiguration") +route53 = get_prop("sam-property-gatewayv2-route53configuration") +domain = get_prop("sam-property-gatewayv2-domainconfiguration") +properties = get_prop("sam-resource-websocketapi") + +""" +Route53 and Domain are the exact same as in httpapi, which is why their get_prop refers to gatewayv2, +but implementing this for the underlying schema causes a failure when make schema checks to see if resources +are subclasses of the generator they're under, so they stay distinct for now. +""" + + +class Route53(BaseModel): + EvaluateTargetHealth: PassThroughProp | None = route53("EvaluateTargetHealth") + HostedZoneId: PassThroughProp | None = route53("HostedZoneId") + HostedZoneName: PassThroughProp | None = route53("HostedZoneName") + IpV6: bool | None = route53("IpV6") + Region: PassThroughProp | None = route53("Region") + SetIdentifier: PassThroughProp | None = route53("SetIdentifier") + + +class Domain(BaseModel): + BasePath: list[str] | None = domain("BasePath") + CertificateArn: PassThroughProp = domain("CertificateArn") + DomainName: PassThroughProp = domain("DomainName") + EndpointConfiguration: SamIntrinsicable[Literal["REGIONAL"]] | None = domain("EndpointConfiguration") + MutualTlsAuthentication: PassThroughProp | None = domain("MutualTlsAuthentication") + OwnershipVerificationCertificateArn: PassThroughProp | None = domain("OwnershipVerificationCertificateArn") + Route53: Route53 | None = domain("Route53") + SecurityPolicy: PassThroughProp | None = domain("SecurityPolicy") + + +class AuthConfig(BaseModel): + AuthArn: SamIntrinsicable[str] | None = auth_spec("AuthArn") + AuthType: PassThroughProp = auth_spec("AuthType") + InvokeRole: SamIntrinsicable[str] | None = auth_spec("InvokeRole") + IdentitySource: PassThroughProp | None = auth_spec("IdentitySource") + Name: PassThroughProp | None = auth_spec("Name") + + +class WebSocketApiRoute(BaseModel): + ApiKeyRequired: PassThroughProp | None = route_spec("ApiKeyRequired") + FunctionArn: SamIntrinsicable[str] = route_spec("FunctionArn") + IntegrationTimeout: PassThroughProp | None = route_spec("IntegrationTimeout") + ModelSelectionExpression: PassThroughProp | None = route_spec("ModelSelectionExpression") + OperationName: PassThroughProp | None = route_spec("OperationName") + RequestModels: PassThroughProp | None = route_spec("RequestModels") + RequestParameters: PassThroughProp | None = route_spec("RequestParameters") + RouteResponseSelectionExpression: PassThroughProp | None = route_spec("RouteResponseSelectionExpression") + + +ApiKeySelectionExpression = PassThroughProp | None +AccessLogSettings = PassThroughProp | None +DefaultRouteSettings = PassThroughProp | None +IpAddressType = PassThroughProp | None +RouteSettings = PassThroughProp | None +RouteSelectionExpression = PassThroughProp | None +StageVariables = PassThroughProp | None +Tags = DictStrAny | None + + +class Properties(BaseModel): + ApiKeySelectionExpression: PassThroughProp | None = properties("ApiKeySelectionExpression") + AccessLogSettings: AccessLogSettings | None = properties("AccessLogSettings") + Auth: AuthConfig | None = properties("Auth") + DefaultRouteSettings: RouteSettings | None = properties("DefaultRouteSettings") + Description: str | None = properties("Description") + DisableExecuteApiEndpoint: PassThroughProp | None = properties("DisableExecuteApiEndpoint") + Domain: Domain | None = properties("Domain") + DisableSchemaValidation: bool | None = properties("DisableSchemaValidation") + IpAddressType: PassThroughProp | None = properties("IpAddressType") + Name: PassThroughProp | None = properties("Name") + PropagateTags: bool | None = properties("PropagateTags") + Routes: dict[str, WebSocketApiRoute] = properties("Routes") + RouteSelectionExpression: PassThroughProp = properties("RouteSelectionExpression") + RouteSettings: RouteSettings | None = properties("RouteSettings") + StageName: PassThroughProp | None = properties("StageName") + StageVariables: StageVariables | None = properties("StageVariables") + Tags: Tags | None = properties("Tags") + + +class Globals(BaseModel): + ApiKeySelectionExpression: str | None = properties("ApiKeySelectionExpression") + AccessLogSettings: AccessLogSettings | None = properties("AccessLogSettings") + DefaultRouteSettings: RouteSettings | None = properties("DefaultRouteSettings") + DisableExecuteApiEndpoint: bool | None = properties("DisableExecuteApiEndpoint") + DisableSchemaValidation: bool | None = properties("DisableSchemaValidation") + Domain: Domain | None = properties("Domain") + IpAddressType: str | None = properties("IpAddressType") + PropagateTags: bool | None = properties("PropagateTags") + RouteSettings: RouteSettings | None = properties("RouteSettings") + RouteSelectionExpression: str | None = properties("RouteSelectionExpression") + StageVariables: StageVariables | None = properties("StageVariables") + Tags: Tags | None = properties("Tags") + + +class Resource(ResourceAttributes): + Type: Literal["AWS::Serverless::WebSocketApi"] + Properties: Properties | None diff --git a/samtranslator/internal/schema_source/sam-docs.json b/samtranslator/internal/schema_source/sam-docs.json index 3b90cc7287..7804e0032c 100644 --- a/samtranslator/internal/schema_source/sam-docs.json +++ b/samtranslator/internal/schema_source/sam-docs.json @@ -563,15 +563,15 @@ "Key": "The Amazon S3 key of the OpenAPI file. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`Key`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-api-bodys3location.html#cfn-apigatewayv2-api-bodys3location-key) property of the `AWS::ApiGatewayV2::Api` `BodyS3Location` data type.", "Version": "For versioned objects, the version of the OpenAPI file. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`Version`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-api-bodys3location.html#cfn-apigatewayv2-api-bodys3location-version) property of the `AWS::ApiGatewayV2::Api` `BodyS3Location` data type." }, - "sam-property-httpapi-httpapidomainconfiguration": { - "BasePath": "A list of the basepaths to configure with the Amazon API Gateway domain name. \n*Type*: List \n*Required*: No \n*Default*: / \n*CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property.", - "CertificateArn": "The Amazon Resource Name (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/ARN.html) of an AWS managed certificate for this domain name's endpoint. AWS Certificate Manager is the only supported source. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource.", - "DomainName": "The custom domain name for your API Gateway API. Uppercase letters are not supported. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name). For information about generated CloudFormation resources, see [Generated 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*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource.", - "EndpointConfiguration": "Defines the type of API Gateway endpoint to map to the custom domain. The value of this property determines how the `CertificateArn` property is mapped in CloudFormation. \nThe only valid value for HTTP APIs is `REGIONAL`. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "MutualTlsAuthentication": "The mutual transport layer security (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/TLS.html) authentication configuration for a custom domain name. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource.", - "OwnershipVerificationCertificateArn": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type.", - "Route53": "Defines an Amazon Route\u00a053 configuration. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "SecurityPolicy": "The TLS version of the security policy for this domain name. \nThe only valid value for HTTP APIs is `TLS_1_2`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type." + "sam-property-gatewayv2-domainconfiguration": { + "BasePath": "A list of the basepaths to configure with the Amazon API Gateway domain name\\. \n*Type*: List \n*Required*: No \n*Default*: / \n*AWS CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource\\. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property\\.", + "CertificateArn": "The Amazon Resource Name \\(ARN\\) of an AWS managed certificate for this domain name's endpoint\\. AWS Certificate Manager is the only supported source\\. \n*Type*: String \n*Required*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource\\.", + "DomainName": "The custom domain name for your API Gateway API\\. Uppercase letters are not supported\\. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set\\. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name)\\. For 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*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource\\.", + "EndpointConfiguration": "Defines the type of API Gateway endpoint to map to the custom domain\\. The value of this property determines how the `CertificateArn` property is mapped in AWS CloudFormation\\. \nThe only valid value for HTTP APIs is `REGIONAL`\\. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "MutualTlsAuthentication": "The mutual transport layer security \\(TLS\\) authentication configuration for a custom domain name\\. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource\\.", + "OwnershipVerificationCertificateArn": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain\\. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", + "Route53": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "SecurityPolicy": "The TLS version of the security policy for this domain name\\. \nThe only valid value for HTTP APIs is `TLS_1_2`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\." }, "sam-property-httpapi-lambdaauthorizationidentity": { "Context": "Converts the given context strings to a list of mapping expressions in the format `$context.contextString`. \n*Type*: List \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", @@ -593,14 +593,14 @@ "IdentitySource": "Identity source expression for this authorizer. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "JwtConfiguration": "JWT configuration for this authorizer. \nThis is passed through to the `jwtConfiguration` section of an `x-amazon-apigateway-authorizer` in the `securitySchemes` section of an OpenAPI definition. \nProperties `issuer` and `audience` are case insensitive and can be used either lowercase as in OpenAPI or uppercase `Issuer` and `Audience` as in [ AWS::ApiGatewayV2::Authorizer](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-authorizer-jwtconfiguration.html). \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent." }, - "sam-property-httpapi-route53configuration": { - "DistributionDomainName": "Configures a custom distribution of the API custom domain name. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution. \n*CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html).", - "EvaluateTargetHealth": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution.", - "HostedZoneId": "The ID of the hosted zone that you want to create records in. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", - "HostedZoneName": "The name of the hosted zone that you want to create records in. You must include a trailing dot (for example, `www.example.com.`) as part of the `HostedZoneName`. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", - "IpV6": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "Region": "*Latency-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region. Route\u00a053 then returns the value that is associated with the selected resource record set. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set.\n+ You can only create one latency resource record set for each Amazon EC2 Region.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for.\n+ You can't create non-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type.", - "SetIdentifier": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme.example.com that have a type of A. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type." + "sam-property-gatewayv2-route53configuration": { + "DistributionDomainName": "Configures a custom distribution of the API custom domain name\\. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution\\. \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html)\\.", + "EvaluateTargetHealth": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution\\.", + "HostedZoneId": "The ID of the hosted zone that you want to create records in\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "HostedZoneName": "The name of the hosted zone that you want to create records in\\. You must include a trailing dot \\(for example, `www.example.com.`\\) as part of the `HostedZoneName`\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "IpV6": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone\\. \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\\.", + "Region": "*Latency\\-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to\\. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type\\. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region\\. Route\u00a053 then returns the value that is associated with the selected resource record set\\. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set\\.\n+ You can only create one latency resource record set for each Amazon EC2 Region\\.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions\\. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for\\.\n+ You can't create non\\-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "SetIdentifier": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme\\.example\\.com that have a type of A\\. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set\\. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\." }, "sam-property-layerversion-layercontent": { "Bucket": "The Amazon S3 bucket of the layer archive. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`S3Bucket`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-layerversion-content.html#cfn-lambda-layerversion-content-s3bucket) property of the `AWS::Lambda::LayerVersion` `Content` data type.", @@ -706,6 +706,24 @@ "StartDate": "The date, in UTC, after which the schedule can begin invoking a target. Depending on the schedule's recurrence expression, invocations might occur on, or after, the StartDate you specify. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StartDate`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html#cfn-scheduler-schedule-startdate) property of an `AWS::Scheduler::Schedule` resource.", "State": "The state of the schedule. \n*Accepted values:* `DISABLED | ENABLED` \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`State`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html#cfn-scheduler-schedule-state) property of an `AWS::Scheduler::Schedule` resource." }, + "sam-property-websocketapi-authconfiguration": { + "AuthArn": "TODO", + "InvokeRole": "TODO", + "AuthType": "TODO", + "PayloadFormatVersion": "TODO", + "IdentitySource": "TODO", + "Name": "TODO" + }, + "sam-property-websocketapi-routeconfiguration": { + "ApiKeyRequired": "TODO", + "FunctionArn": "TODO", + "IntegrationTimeout": "TODO", + "ModelSelectionExpression": "TODO", + "OperationName": "TODO", + "RequestModels": "TODO", + "RequestParameters": "TODO", + "RouteResponseSelectionExpression": "TODO" + }, "sam-property-statemachine-statemachinetarget": { "Id": "The logical ID of the target. \nThe value of `Id` can include alphanumeric characters, periods (`.`), hyphens (`-`), and underscores (`_`). \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`Id`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-id) property of the `AWS::Events::Rule` `Target` data type." }, @@ -834,22 +852,22 @@ "XrayEnabled": "Indicate whether to use [AWS X-Ray tracing](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html) for this resource. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`XrayEnabled`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-graphqlapi.html#cfn-appsync-graphqlapi-xrayenabled) property of an `AWS::AppSync::GraphQLApi` resource." }, "sam-resource-httpapi": { - "AccessLogSettings": "The settings for access logging in a stage. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource.", - "Auth": "Configures authorization for controlling access to your API Gateway HTTP API. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "CorsConfiguration": "Manages cross-origin resource sharing (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html) for all your API Gateway HTTP APIs. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object. Note that https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html requires AWS SAM to modify your OpenAPI definition, so https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html works only if the `DefinitionBody` property is specified. \nFor more information, see [Configuring https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence. If this property is set to `true`, then all origins are allowed.\n*Type*: String \\$1 [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "DefaultRouteSettings": "The default route settings for this HTTP API. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", - "DefinitionBody": "The OpenAPI definition that describes your HTTP API. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \n*Type*: JSON \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to CloudFormation. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource.", - "DefinitionUri": "The Amazon Simple Storage Service (Amazon S3) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API. The Amazon S3 object that this property references must be a valid OpenAPI definition file. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html). \n*Type*: String \\$1 [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource. The nested Amazon S3 properties are named differently.", - "Description": "The description of the HTTP API resource. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "DisableExecuteApiEndpoint": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`. By default, clients can invoke your API with the default endpoint. To require that clients only use a custom domain name to invoke your API, disable the default endpoint. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x-amazon-apigateway-endpoint-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource.", - "Domain": "Configures a custom domain for this API Gateway HTTP API. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "FailOnWarnings": "Specifies whether to roll back the HTTP API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource.", - "Name": "The name of the HTTP API resource. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "RouteSettings": "The route settings, per route, for this HTTP API. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", - "StageName": "The name of the API stage. If no name is specified, AWS SAM uses the `$default` stage from API Gateway. \n*Type*: String \n*Required*: No \n*Default*: \\$1default \n*CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource.", - "StageVariables": "A map that defines the stage variables. Variable names can have alphanumeric and underscore characters. The values must match [A-Za-z0-9-.\\$1\\$1:/?\\$1&=,]\\$1. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource.", - "Tags": "A map (string to string) that specifies the tags to add to this API Gateway stage. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`. Values can be 1 to 256 Unicode characters in length. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource (if `DomainName` is specified)." + "AccessLogSettings": "The settings for access logging in a stage\\. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", + "Auth": "Configures authorization for controlling access to your API Gateway HTTP API\\. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*\\. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "CorsConfiguration": "Manages cross\\-origin resource sharing \\(CORS\\) for all your API Gateway HTTP APIs\\. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object\\. Note that CORS requires AWS SAM to modify your OpenAPI definition, so CORS works only if the `DefinitionBody` property is specified\\. \nFor more information, see [Configuring CORS for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*\\. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence\\. If this property is set to `true`, then all origins are allowed\\.\n*Type*: String \\| [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "DefaultRouteSettings": "The default route settings for this HTTP API\\. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", + "DefinitionBody": "The OpenAPI definition that describes your HTTP API\\. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \n*Type*: JSON \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource\\. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to AWS CloudFormation\\. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource\\.", + "DefinitionUri": "The Amazon Simple Storage Service \\(Amazon S3\\) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API\\. The Amazon S3 object that this property references must be a valid OpenAPI definition file\\. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly\\. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`\\. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html)\\. \n*Type*: String \\| [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource\\. The nested Amazon S3 properties are named differently\\.", + "Description": "The description of the HTTP API resource\\. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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\\.", + "DisableExecuteApiEndpoint": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`\\. By default, clients can invoke your API with the default endpoint\\. To require that clients only use a custom domain name to invoke your API, disable the default endpoint\\. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource\\. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x\\-amazon\\-apigateway\\-endpoint\\-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource\\.", + "Domain": "Configures a custom domain for this API Gateway HTTP API\\. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "FailOnWarnings": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.", + "Name": "The name of the HTTP API resource\\. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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\\.", + "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.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\\.", + "RouteSettings": "The route settings, per route, for this HTTP API\\. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", + "StageName": "The name of the API stage\\. If no name is specified, AWS SAM uses the `$default` stage from API Gateway\\. \n*Type*: String \n*Required*: No \n*Default*: $default \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource\\.", + "StageVariables": "A map that defines the stage variables\\. Variable names can have alphanumeric and underscore characters\\. The values must match \\[A\\-Za\\-z0\\-9\\-\\.\\_\\~:/?\\#&=,\\]\\+\\. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource\\.", + "Tags": "A map \\(string to string\\) that specifies the tags to add to this API Gateway stage\\. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`\\. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`\\. Values can be 1 to 256 Unicode characters in length\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified\\. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag\\. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource \\(if `DomainName` is specified\\)\\." }, "sam-resource-layerversion": { "CompatibleArchitectures": "Specifies the supported instruction set architectures for the layer version. \nFor more information about this property, see [Lambda instruction set architectures](https://docs.aws.amazon.com/lambda/latest/dg/foundation-arch.html) in the *AWS Lambda Developer Guide*. \n*Valid values*: `x86_64`, `arm64` \n*Type*: List \n*Required*: No \n*Default*: `x86_64` \n*CloudFormation compatibility*: This property is passed directly to the [`CompatibleArchitectures`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html#cfn-lambda-layerversion-compatiblearchitectures) property of an `AWS::Lambda::LayerVersion` resource.", @@ -870,23 +888,43 @@ "Tags": "A map (string to string) that specifies the tags to be added to this SimpleTable. For details about valid keys and values for tags, see [Resource tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) in the *AWS CloudFormation User Guide*. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-tags) property of an `AWS::DynamoDB::Table` resource. The Tags property in SAM consists of Key:Value pairs; in CloudFormation it consists of a list of Tag objects." }, "sam-resource-statemachine": { - "AutoPublishAlias": "The name of the state machine alias. To learn more about using Step Functions state machine aliases, see [ Manage continuous deployments with versions and aliases](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-cd-aliasing-versioning.html) in the *AWS Step Functions Developer Guide*. \nUse `DeploymentPreference` to configure deployment preferences for your alias. If you don\u2019t specify `DeploymentPreference`, AWS SAM will configure traffic to shift to the newer state machine version all at once. \nAWS SAM sets the version\u2019s `DeletionPolicy` and `UpdateReplacePolicy` to `Retain` by default. Previous versions will not be deleted automatically. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the ` [ Name](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachinealias.html#cfn-stepfunctions-statemachinealias-name)` property of an `AWS::StepFunctions::StateMachineAlias` resource.", - "Definition": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples). \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: Map \n*Required*: Conditional \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "DefinitionSubstitutions": "A string-to-string map that specifies the mappings for placeholder variables in the state machine definition. This enables you to inject values obtained at runtime (for example, from intrinsic functions) into the state machine definition. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition.", - "DefinitionUri": "The Amazon Simple Storage Service (Amazon S3) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition. To do this, you must use version 0.52.0 or later of the AWS SAM CLI. \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: String \\$1 [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource.", - "DeploymentPreference": "The settings that enable and configure gradual state machine deployments. To learn more about Step Functions gradual deployments, see [ Manage continuous deployments with versions and aliases](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-cd-aliasing-versioning.html) in the *AWS Step Functions Developer Guide*. \nSpecify `AutoPublishAlias` before configuring this property. Your `DeploymentPreference` settings will be applied to the alias specified with `AutoPublishAlias`. \nWhen you specify `DeploymentPreference`, AWS SAM generates the `StateMachineVersionArn` sub-property value automatically. \n*Type*: [DeploymentPreference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachinealias-deploymentpreference.html) \n*Required*: No \n*CloudFormation compatibility*: AWS SAM generates and attaches the `StateMachineVersionArn` property value to `DeploymentPreference` and passes `DeploymentPreference` to the [`DeploymentPreference`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachinealias.html#cfn-stepfunctions-statemachinealias-deploymentpreference) property of an `AWS::StepFunctions::StateMachineAlias` resource.", - "Events": "Specifies the events that trigger this state machine. Events consist of a type and a set of properties that depend on the type. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "Logging": "Defines which execution history events are logged and where they are logged. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", - "Name": "The name of the state machine. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource.", - "PermissionsBoundary": "The ARN of a permissions boundary to use for this state machine's execution role. This property only works if the role is generated for you. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource.", - "Policies": "Permission policies for this state machine. Policies will be appended to the state machine's default AWS Identity and Access Management (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html) 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/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) or [customer managed policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 \\$1 List \\$1 Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", - "Role": "The ARN of an IAM role to use as this state machine's execution role. \n*Type*: String \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource.", - "RolePath": "The path to the state machine'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*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.", - "Tags": "A string-to-string map that specifies the tags added to the state machine and the corresponding execution role. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it.", - "Tracing": "Selects whether or not AWS X-Ray is enabled for the state machine. For more information about using X-Ray with Step Functions, see [AWS X-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", - "Type": "The type of the state machine. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource.", - "UseAliasAsEventTarget": "Indicate whether or not to pass the alias, created by using the `AutoPublishAlias` property, to the events source's target defined with [Events](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-statemachine-events.html#sam-statemachine-events). \nSpecify `True` to use the alias as the events' target. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent." + "AutoPublishAlias": "The name of the state machine alias\\. To learn more about using Step Functions state machine aliases, see [ Manage continuous deployments with versions and aliases](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-cd-aliasing-versioning.html) in the *AWS Step Functions Developer Guide*\\. \nUse `DeploymentPreference` to configure deployment preferences for your alias\\. If you don\u2019t specify `DeploymentPreference`, AWS SAM will configure traffic to shift to the newer state machine version all at once\\. \nAWS SAM sets the version\u2019s `DeletionPolicy` and `UpdateReplacePolicy` to `Retain` by default\\. Previous versions will not be deleted automatically\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the ` [ Name](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachinealias.html#cfn-stepfunctions-statemachinealias-name)` property of an `AWS::StepFunctions::StateMachineAlias` resource\\.", + "Definition": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML\\. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples)\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: Map \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "DefinitionSubstitutions": "A string\\-to\\-string map that specifies the mappings for placeholder variables in the state machine definition\\. This enables you to inject values obtained at runtime \\(for example, from intrinsic functions\\) into the state machine definition\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource\\. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition\\.", + "DefinitionUri": "The Amazon Simple Storage Service \\(Amazon S3\\) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition\\. To do this, you must use version 0\\.52\\.0 or later of the AWS SAM CLI\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: String \\| [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource\\.", + "DeploymentPreference": "The settings that enable and configure gradual state machine deployments\\. To learn more about Step Functions gradual deployments, see [ Manage continuous deployments with versions and aliases](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-cd-aliasing-versioning.html) in the *AWS Step Functions Developer Guide*\\. \nSpecify `AutoPublishAlias` before configuring this property\\. Your `DeploymentPreference` settings will be applied to the alias specified with `AutoPublishAlias`\\. \nWhen you specify `DeploymentPreference`, AWS SAM generates the `StateMachineVersionArn` sub\\-property value automatically\\. \n*Type*: [DeploymentPreference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachinealias-deploymentpreference.html) \n*Required*: No \n*AWS CloudFormation compatibility*: AWS SAM generates and attaches the `StateMachineVersionArn` property value to `DeploymentPreference` and passes `DeploymentPreference` to the [`DeploymentPreference`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachinealias.html#cfn-stepfunctions-statemachinealias-deploymentpreference) property of an `AWS::StepFunctions::StateMachineAlias` resource\\.", + "Events": "Specifies the events that trigger this state machine\\. Events consist of a type and a set of properties that depend on the type\\. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "Logging": "Defines which execution history events are logged and where they are logged\\. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", + "Name": "The name of the state machine\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource\\.", + "PermissionsBoundary": "The ARN of a permissions boundary to use for this state machine's execution role\\. This property only works if the role is generated for you\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource\\.", + "Policies": "Permission policies for this state machine\\. Policies will be appended to the state machine'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 unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "PropagateTags": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.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\\.", + "Role": "The ARN of an IAM role to use as this state machine's execution role\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource\\.", + "RolePath": "The path to the state machine'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\\.", + "Tags": "A string\\-to\\-string map that specifies the tags added to the state machine and the corresponding execution role\\. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource\\. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it\\.", + "Tracing": "Selects whether or not AWS X\\-Ray is enabled for the state machine\\. For more information about using X\\-Ray with Step Functions, see [AWS X\\-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*\\. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", + "Type": "The type of the state machine\\. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource\\.", + "UseAliasAsEventTarget": "Indicate whether or not to pass the alias, created by using the `AutoPublishAlias` property, to the events source's target defined with [Events](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-statemachine-events.html#sam-statemachine-events)\\. \nSpecify `True` to use the alias as the events' target\\. \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\\." + }, + "sam-resource-websocketapi": { + "ApiKeySelectionExpression": "TODO", + "AccessLogSettings": "TODO", + "Auth": "TODO", + "DefaultRouteSettings": "TODO", + "Description": "TODO", + "DisableExecuteApiEndpoint": "TODO", + "DisableSchemaValidation": "TODO", + "Domain": "TODO", + "FailOnWarnings": "TODO", + "IpAddressType": "TODO", + "Name": "TODO", + "PropagateTags": "TODO", + "Routes": "TODO", + "RouteSelectionExpression": "TODO", + "RouteSettings": "TODO", + "StageName": "TODO", + "StageVariables": "TODO", + "Tags": "TODO" } } } \ No newline at end of file diff --git a/samtranslator/internal/schema_source/schema.py b/samtranslator/internal/schema_source/schema.py index 2b642504bc..3cf05c30e5 100644 --- a/samtranslator/internal/schema_source/schema.py +++ b/samtranslator/internal/schema_source/schema.py @@ -20,6 +20,7 @@ aws_serverless_layerversion, aws_serverless_simpletable, aws_serverless_statemachine, + aws_serverless_websocketapi, ) from samtranslator.internal.schema_source.common import BaseModel, LenientBaseModel @@ -28,6 +29,7 @@ class Globals(BaseModel): Function: aws_serverless_function.Globals | None Api: aws_serverless_api.Globals | None HttpApi: aws_serverless_httpapi.Globals | None + WebSocketApi: aws_serverless_websocketapi.Globals | None SimpleTable: aws_serverless_simpletable.Globals | None StateMachine: aws_serverless_statemachine.Globals | None LayerVersion: aws_serverless_layerversion.Globals | None @@ -42,6 +44,7 @@ class Globals(BaseModel): aws_serverless_layerversion.Resource, aws_serverless_api.Resource, aws_serverless_httpapi.Resource, + aws_serverless_websocketapi.Resource, aws_serverless_application.Resource, aws_serverless_graphqlapi.Resource, aws_serverless_capacity_provider.Resource, diff --git a/samtranslator/model/api/apiv2_generator.py b/samtranslator/model/api/apiv2_generator.py new file mode 100644 index 0000000000..9c6c18627c --- /dev/null +++ b/samtranslator/model/api/apiv2_generator.py @@ -0,0 +1,303 @@ +import re +from typing import Any, cast + +from samtranslator.model.apigatewayv2 import ApiGatewayV2Api, ApiGatewayV2ApiMapping, ApiGatewayV2DomainName +from samtranslator.model.exceptions import InvalidResourceException +from samtranslator.model.intrinsics import fnGetAtt, fnSub, ref +from samtranslator.model.lambda_ import LambdaPermission +from samtranslator.model.route53 import Route53RecordSetGroup +from samtranslator.translator.arn_generator import ArnGenerator +from samtranslator.translator.logical_id_generator import LogicalIdGenerator +from samtranslator.utils.types import Intrinsicable +from samtranslator.validator.value_validator import sam_expect + + +class ApiV2Generator: + def __init__( # noqa: PLR0913 + self, + logical_id: str, + stage_variables: dict[str, Intrinsicable[str]] | None, + depends_on: list[str] | None, + access_log_settings: dict[str, Intrinsicable[str]] | None = None, + default_route_settings: dict[str, Any] | None = None, + description: Intrinsicable[str] | None = None, + disable_execute_api_endpoint: Intrinsicable[bool] | None = None, + domain: dict[str, Any] | None = None, + # ip address type? + passthrough_resource_attributes: dict[str, Intrinsicable[str]] | None = None, + resource_attributes: dict[str, Intrinsicable[str]] | None = None, + route_settings: dict[str, Any] | None = None, + tags: dict[str, Intrinsicable[str]] | None = None, + ) -> None: + """Constructs an API Generator class that generates API Gateway resources + + :param logical_id: Logical id of the SAM API Resource + :param stage_variables: API Gateway Variables + :param depends_on: Any resources that need to be depended on + :param description: Description of the API Gateway resource + :param access_log_settings: Whether to send access logs and where for Stage + :param passthrough_resource_attributes: Attributes such as 'Condition' that are added to derived resources + :param resource_attributes: Resource attributes to add to API resources + :param tags: Stage and API Tags + """ + self.logical_id = logical_id + self.stage_variables = stage_variables + self.depends_on = depends_on + self.access_log_settings = access_log_settings + self.default_route_settings = default_route_settings + self.description = description + self.disable_execute_api_endpoint = disable_execute_api_endpoint + self.domain = domain + self.passthrough_resource_attributes = passthrough_resource_attributes + self.resource_attributes = resource_attributes + self.route_settings = route_settings + self.tags = tags + self.default_tag_name = "" + + def _construct_api_domain( # noqa: PLR0912, PLR0915 + self, api: ApiGatewayV2Api, route53_record_set_groups: dict[str, Route53RecordSetGroup] + ) -> tuple[ + ApiGatewayV2DomainName | None, + list[ApiGatewayV2ApiMapping] | None, + Route53RecordSetGroup | None, + ]: + """ + Constructs and returns the ApiGateway Domain and BasepathMapping + """ + if self.domain is None: + return None, None, None + + custom_domain_config = self.domain # not creating a copy as we will mutate it + domain_name = custom_domain_config.get("DomainName") + + domain_name_config = {} + + certificate_arn = custom_domain_config.get("CertificateArn") + if domain_name is None or certificate_arn is None: + raise InvalidResourceException( + self.logical_id, "Custom Domains only works if both DomainName and CertificateArn are provided." + ) + domain_name_config["CertificateArn"] = certificate_arn + + api_domain_name = "{}{}".format("ApiGatewayDomainNameV2", LogicalIdGenerator("", domain_name).gen()) + custom_domain_config["ApiDomainName"] = api_domain_name + + domain = ApiGatewayV2DomainName(api_domain_name, attributes=self.passthrough_resource_attributes) + domain.DomainName = domain_name + if self.default_tag_name != "": + domain.Tags = {self.default_tag_name: "SAM"} + + endpoint_config = custom_domain_config.get("EndpointConfiguration") + if endpoint_config is None: + endpoint_config = "REGIONAL" + # to make sure that default is always REGIONAL + custom_domain_config["EndpointConfiguration"] = "REGIONAL" + elif endpoint_config not in ["REGIONAL"]: + raise InvalidResourceException( + self.logical_id, + "EndpointConfiguration for Custom Domains must be one of {}.".format(["REGIONAL"]), + ) + domain_name_config["EndpointType"] = endpoint_config + + ownership_verification_certificate_arn = custom_domain_config.get("OwnershipVerificationCertificateArn") + if ownership_verification_certificate_arn: + domain_name_config["OwnershipVerificationCertificateArn"] = ownership_verification_certificate_arn + + security_policy = custom_domain_config.get("SecurityPolicy") + if security_policy: + domain_name_config["SecurityPolicy"] = security_policy + + domain.DomainNameConfigurations = [domain_name_config] + + mutual_tls_auth = custom_domain_config.get("MutualTlsAuthentication", None) + if mutual_tls_auth: + if isinstance(mutual_tls_auth, dict): + if not set(mutual_tls_auth.keys()).issubset({"TruststoreUri", "TruststoreVersion"}): + invalid_keys = [] + for key in mutual_tls_auth: + if key not in {"TruststoreUri", "TruststoreVersion"}: + invalid_keys.append(key) + invalid_keys.sort() + raise InvalidResourceException( + ",".join(invalid_keys), + "Available MutualTlsAuthentication fields are {}.".format( + ["TruststoreUri", "TruststoreVersion"] + ), + ) + domain.MutualTlsAuthentication = {} + if mutual_tls_auth.get("TruststoreUri", None): + domain.MutualTlsAuthentication["TruststoreUri"] = mutual_tls_auth["TruststoreUri"] + if mutual_tls_auth.get("TruststoreVersion", None): + domain.MutualTlsAuthentication["TruststoreVersion"] = mutual_tls_auth["TruststoreVersion"] + else: + raise InvalidResourceException( + self.logical_id, + "MutualTlsAuthentication must be a map with at least one of the following fields {}.".format( + ["TruststoreUri", "TruststoreVersion"] + ), + ) + + # Create BasepathMappings + basepaths: list[str] | None + basepath_value = self.domain.get("BasePath") + if basepath_value and isinstance(basepath_value, str): + basepaths = [basepath_value] + elif basepath_value and isinstance(basepath_value, list): + basepaths = cast(list[str] | None, basepath_value) + else: + basepaths = None + basepath_resource_list = self._construct_basepath_mappings(basepaths, api, api_domain_name) + + # Create the Route53 RecordSetGroup resource + record_set_group = self._construct_route53_recordsetgroup( + self.domain, route53_record_set_groups, api_domain_name + ) + + return domain, basepath_resource_list, record_set_group + + def _construct_route53_recordsetgroup( + self, + custom_domain_config: dict[str, Any], + route53_record_set_groups: dict[str, Route53RecordSetGroup], + api_domain_name: str, + ) -> Route53RecordSetGroup | None: + route53_config = custom_domain_config.get("Route53") + if route53_config is None: + return None + sam_expect(route53_config, self.logical_id, "Domain.Route53").to_be_a_map() + if route53_config.get("HostedZoneId") is None and route53_config.get("HostedZoneName") is None: + raise InvalidResourceException( + self.logical_id, + "HostedZoneId or HostedZoneName is required to enable Route53 support on Custom Domains.", + ) + + logical_id_suffix = LogicalIdGenerator( + "", route53_config.get("HostedZoneId") or route53_config.get("HostedZoneName") + ).gen() + logical_id = "RecordSetGroup" + logical_id_suffix + + matching_record_set_group = route53_record_set_groups.get(logical_id) + if matching_record_set_group: + record_set_group = matching_record_set_group + else: + record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) + if "HostedZoneId" in route53_config: + record_set_group.HostedZoneId = route53_config.get("HostedZoneId") + elif "HostedZoneName" in route53_config: + record_set_group.HostedZoneName = route53_config.get("HostedZoneName") + record_set_group.RecordSets = [] + route53_record_set_groups[logical_id] = record_set_group + + if record_set_group.RecordSets is None: + record_set_group.RecordSets = [] + record_set_group.RecordSets += self._construct_record_sets_for_domain( + custom_domain_config, route53_config, api_domain_name + ) + return record_set_group + + def _construct_basepath_mappings( + self, basepaths: list[str] | None, api: ApiGatewayV2Api, api_domain_name: str + ) -> list[ApiGatewayV2ApiMapping]: + basepath_resource_list: list[ApiGatewayV2ApiMapping] = [] + + if basepaths is None: + basepath_mapping = ApiGatewayV2ApiMapping( + self.logical_id + "ApiMapping", attributes=self.passthrough_resource_attributes + ) + basepath_mapping.DomainName = ref(api_domain_name) + basepath_mapping.ApiId = ref(api.logical_id) + basepath_mapping.Stage = ref(api.logical_id + ".Stage") + basepath_resource_list.extend([basepath_mapping]) + else: + for path in basepaths: + # search for invalid characters in the path and raise error if there are + invalid_regex = r"[^0-9a-zA-Z\/\-\_]+" + + if not isinstance(path, str): + raise InvalidResourceException(self.logical_id, "Basepath must be a string.") + + if re.search(invalid_regex, path) is not None: + raise InvalidResourceException(self.logical_id, "Invalid Basepath name provided.") + + logical_id = "{}{}{}".format(self.logical_id, re.sub(r"[\-_/]+", "", path), "ApiMapping") + basepath_mapping = ApiGatewayV2ApiMapping(logical_id, attributes=self.passthrough_resource_attributes) + basepath_mapping.DomainName = ref(api_domain_name) + basepath_mapping.ApiId = ref(api.logical_id) + basepath_mapping.Stage = ref(api.logical_id + ".Stage") + # ignore leading and trailing `/` in the path name + basepath_mapping.ApiMappingKey = path.strip("/") + basepath_resource_list.extend([basepath_mapping]) + return basepath_resource_list + + def _construct_record_sets_for_domain( + self, custom_domain_config: dict[str, Any], route53_config: dict[str, Any], api_domain_name: str + ) -> list[dict[str, Any]]: + recordset_list = [] + + recordset = {} + recordset["Name"] = custom_domain_config.get("DomainName") + recordset["Type"] = "A" + recordset["AliasTarget"] = self._construct_alias_target(custom_domain_config, route53_config, api_domain_name) + self._update_route53_routing_policy_properties(route53_config, recordset) + recordset_list.append(recordset) + + if route53_config.get("IpV6") is not None and route53_config.get("IpV6") is True: + recordset_ipv6 = {} + recordset_ipv6["Name"] = custom_domain_config.get("DomainName") + recordset_ipv6["Type"] = "AAAA" + recordset_ipv6["AliasTarget"] = self._construct_alias_target( + custom_domain_config, route53_config, api_domain_name + ) + self._update_route53_routing_policy_properties(route53_config, recordset_ipv6) + recordset_list.append(recordset_ipv6) + + return recordset_list + + @staticmethod + def _update_route53_routing_policy_properties(route53_config: dict[str, Any], recordset: dict[str, Any]) -> None: + if route53_config.get("Region") is not None: + recordset["Region"] = route53_config.get("Region") + if route53_config.get("SetIdentifier") is not None: + recordset["SetIdentifier"] = route53_config.get("SetIdentifier") + + def _construct_alias_target( + self, domain_config: dict[str, Any], route53_config: dict[str, Any], api_domain_name: str + ) -> dict[str, Any]: + alias_target = {} + target_health = route53_config.get("EvaluateTargetHealth") + + if target_health is not None: + alias_target["EvaluateTargetHealth"] = target_health + if domain_config.get("EndpointConfiguration") == "REGIONAL": + alias_target["HostedZoneId"] = fnGetAtt(api_domain_name, "RegionalHostedZoneId") + alias_target["DNSName"] = fnGetAtt(api_domain_name, "RegionalDomainName") + else: + raise InvalidResourceException( + self.logical_id, + "Only REGIONAL endpoint is supported on HTTP APIs.", + ) + return alias_target + + def _get_authorizer_permission( + self, permission_name: str, authorizer_lambda_function_arn: str, api_id: Any + ) -> LambdaPermission: + """Constructs and returns the Lambda Permission resource allowing API Gateway to invoke the authorizer. + + :param permission_name: logical ID for the permission resource + :param authorizer_lambda_function_arn: ARN of the authorizer Lambda function + :param api_id: API resource reference (Ref or GetAtt) + :returns: the permission resource + """ + resource = "${__ApiId__}/authorizers/*" + source_arn = fnSub( + ArnGenerator.generate_arn(partition="${AWS::Partition}", service="execute-api", resource=resource), + {"__ApiId__": api_id}, + ) + + lambda_permission = LambdaPermission(permission_name, attributes=self.passthrough_resource_attributes) + lambda_permission.Action = "lambda:InvokeFunction" + lambda_permission.FunctionName = authorizer_lambda_function_arn + lambda_permission.Principal = "apigateway.amazonaws.com" + lambda_permission.SourceArn = source_arn + + return lambda_permission diff --git a/samtranslator/model/api/http_api_generator.py b/samtranslator/model/api/http_api_generator.py index b2ac75256b..d0c0cdec92 100644 --- a/samtranslator/model/api/http_api_generator.py +++ b/samtranslator/model/api/http_api_generator.py @@ -1,8 +1,8 @@ -import re from collections import namedtuple -from typing import Any, Union, cast +from typing import Any, Union from samtranslator.metrics.method_decorator import cw_timer +from samtranslator.model.api.apiv2_generator import ApiV2Generator from samtranslator.model.apigatewayv2 import ( ApiGatewayV2ApiMapping, ApiGatewayV2Authorizer, @@ -11,12 +11,11 @@ ApiGatewayV2Stage, ) from samtranslator.model.exceptions import InvalidResourceException -from samtranslator.model.intrinsics import fnGetAtt, fnSub, is_intrinsic, is_intrinsic_no_value, ref +from samtranslator.model.intrinsics import is_intrinsic, is_intrinsic_no_value, ref from samtranslator.model.lambda_ import LambdaPermission from samtranslator.model.route53 import Route53RecordSetGroup from samtranslator.model.s3_utils.uri_parser import parse_s3_uri from samtranslator.open_api.open_api import OpenApiEditor -from samtranslator.translator.arn_generator import ArnGenerator from samtranslator.translator.logical_id_generator import LogicalIdGenerator from samtranslator.utils.types import Intrinsicable from samtranslator.utils.utils import InvalidValueType, dict_deep_get @@ -34,7 +33,7 @@ HttpApiTagName = "httpapi:createdBy" -class HttpApiGenerator: +class HttpApiGenerator(ApiV2Generator): def __init__( # noqa: PLR0913 self, logical_id: str, @@ -72,27 +71,30 @@ def __init__( # noqa: PLR0913 :param passthrough_resource_attributes: Attributes such as `Condition` that are added to derived resources :param description: Description of the API Gateway resource """ - self.logical_id = logical_id - self.stage_variables = stage_variables - self.depends_on = depends_on + super().__init__( + logical_id, + stage_variables, + depends_on, + access_log_settings, + default_route_settings, + description, + disable_execute_api_endpoint, + domain, + passthrough_resource_attributes, + resource_attributes, + route_settings, + tags, + ) self.definition_body = definition_body self.definition_uri = definition_uri - self.stage_name = stage_name + self.fail_on_warnings = fail_on_warnings self.name = name + self.stage_name = stage_name if not self.stage_name: self.stage_name = DefaultStageName self.auth = auth self.cors_configuration = cors_configuration - self.tags = tags - self.access_log_settings = access_log_settings - self.route_settings = route_settings - self.default_route_settings = default_route_settings - self.resource_attributes = resource_attributes - self.passthrough_resource_attributes = passthrough_resource_attributes - self.domain = domain - self.fail_on_warnings = fail_on_warnings - self.description = description - self.disable_execute_api_endpoint = disable_execute_api_endpoint + self.default_tag_name = HttpApiTagName def _construct_http_api(self) -> ApiGatewayV2HttpApi: """Constructs and returns the ApiGatewayV2 HttpApi. @@ -240,229 +242,6 @@ def _update_default_path(self) -> None: if DefaultStageName in paths: paths[f"/{DefaultStageName}"] = paths.pop(DefaultStageName) - def _construct_api_domain( # noqa: PLR0912, PLR0915 - self, http_api: ApiGatewayV2HttpApi, route53_record_set_groups: dict[str, Route53RecordSetGroup] - ) -> tuple[ - ApiGatewayV2DomainName | None, - list[ApiGatewayV2ApiMapping] | None, - Route53RecordSetGroup | None, - ]: - """ - Constructs and returns the ApiGateway Domain and BasepathMapping - """ - if self.domain is None: - return None, None, None - - custom_domain_config = self.domain # not creating a copy as we will mutate it - domain_name = custom_domain_config.get("DomainName") - - domain_name_config = {} - - certificate_arn = custom_domain_config.get("CertificateArn") - if domain_name is None or certificate_arn is None: - raise InvalidResourceException( - self.logical_id, "Custom Domains only works if both DomainName and CertificateArn are provided." - ) - domain_name_config["CertificateArn"] = certificate_arn - - api_domain_name = "{}{}".format("ApiGatewayDomainNameV2", LogicalIdGenerator("", domain_name).gen()) - custom_domain_config["ApiDomainName"] = api_domain_name - - domain = ApiGatewayV2DomainName(api_domain_name, attributes=self.passthrough_resource_attributes) - domain.DomainName = domain_name - domain.Tags = self.tags - - endpoint_config = custom_domain_config.get("EndpointConfiguration") - if endpoint_config is None: - endpoint_config = "REGIONAL" - # to make sure that default is always REGIONAL - custom_domain_config["EndpointConfiguration"] = "REGIONAL" - elif endpoint_config not in ["REGIONAL"]: - raise InvalidResourceException( - self.logical_id, - "EndpointConfiguration for Custom Domains must be one of {}.".format(["REGIONAL"]), - ) - domain_name_config["EndpointType"] = endpoint_config - - ownership_verification_certificate_arn = custom_domain_config.get("OwnershipVerificationCertificateArn") - if ownership_verification_certificate_arn: - domain_name_config["OwnershipVerificationCertificateArn"] = ownership_verification_certificate_arn - - security_policy = custom_domain_config.get("SecurityPolicy") - if security_policy: - domain_name_config["SecurityPolicy"] = security_policy - - domain.DomainNameConfigurations = [domain_name_config] - - mutual_tls_auth = custom_domain_config.get("MutualTlsAuthentication", None) - if mutual_tls_auth: - if isinstance(mutual_tls_auth, dict): - if not set(mutual_tls_auth.keys()).issubset({"TruststoreUri", "TruststoreVersion"}): - invalid_keys = [] - for key in mutual_tls_auth: - if key not in {"TruststoreUri", "TruststoreVersion"}: - invalid_keys.append(key) - invalid_keys.sort() - raise InvalidResourceException( - ",".join(invalid_keys), - "Available MutualTlsAuthentication fields are {}.".format( - ["TruststoreUri", "TruststoreVersion"] - ), - ) - domain.MutualTlsAuthentication = {} - if mutual_tls_auth.get("TruststoreUri", None): - domain.MutualTlsAuthentication["TruststoreUri"] = mutual_tls_auth["TruststoreUri"] - if mutual_tls_auth.get("TruststoreVersion", None): - domain.MutualTlsAuthentication["TruststoreVersion"] = mutual_tls_auth["TruststoreVersion"] - else: - raise InvalidResourceException( - self.logical_id, - "MutualTlsAuthentication must be a map with at least one of the following fields {}.".format( - ["TruststoreUri", "TruststoreVersion"] - ), - ) - - # Create BasepathMappings - basepaths: list[str] | None - basepath_value = self.domain.get("BasePath") - if basepath_value and isinstance(basepath_value, str): - basepaths = [basepath_value] - elif basepath_value and isinstance(basepath_value, list): - basepaths = cast(list[str] | None, basepath_value) - else: - basepaths = None - basepath_resource_list = self._construct_basepath_mappings(basepaths, http_api, api_domain_name) - - # Create the Route53 RecordSetGroup resource - record_set_group = self._construct_route53_recordsetgroup( - self.domain, route53_record_set_groups, api_domain_name - ) - - return domain, basepath_resource_list, record_set_group - - def _construct_route53_recordsetgroup( - self, - custom_domain_config: dict[str, Any], - route53_record_set_groups: dict[str, Route53RecordSetGroup], - api_domain_name: str, - ) -> Route53RecordSetGroup | None: - route53_config = custom_domain_config.get("Route53") - if route53_config is None: - return None - sam_expect(route53_config, self.logical_id, "Domain.Route53").to_be_a_map() - if route53_config.get("HostedZoneId") is None and route53_config.get("HostedZoneName") is None: - raise InvalidResourceException( - self.logical_id, - "HostedZoneId or HostedZoneName is required to enable Route53 support on Custom Domains.", - ) - - logical_id_suffix = LogicalIdGenerator( - "", route53_config.get("HostedZoneId") or route53_config.get("HostedZoneName") - ).gen() - logical_id = "RecordSetGroup" + logical_id_suffix - - matching_record_set_group = route53_record_set_groups.get(logical_id) - if matching_record_set_group: - record_set_group = matching_record_set_group - else: - record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) - if "HostedZoneId" in route53_config: - record_set_group.HostedZoneId = route53_config.get("HostedZoneId") - elif "HostedZoneName" in route53_config: - record_set_group.HostedZoneName = route53_config.get("HostedZoneName") - record_set_group.RecordSets = [] - route53_record_set_groups[logical_id] = record_set_group - - if record_set_group.RecordSets is None: - record_set_group.RecordSets = [] - record_set_group.RecordSets += self._construct_record_sets_for_domain( - custom_domain_config, route53_config, api_domain_name - ) - return record_set_group - - def _construct_basepath_mappings( - self, basepaths: list[str] | None, http_api: ApiGatewayV2HttpApi, api_domain_name: str - ) -> list[ApiGatewayV2ApiMapping]: - basepath_resource_list: list[ApiGatewayV2ApiMapping] = [] - - if basepaths is None: - basepath_mapping = ApiGatewayV2ApiMapping( - self.logical_id + "ApiMapping", attributes=self.passthrough_resource_attributes - ) - basepath_mapping.DomainName = ref(api_domain_name) - basepath_mapping.ApiId = ref(http_api.logical_id) - basepath_mapping.Stage = ref(http_api.logical_id + ".Stage") - basepath_resource_list.extend([basepath_mapping]) - else: - for path in basepaths: - # search for invalid characters in the path and raise error if there are - invalid_regex = r"[^0-9a-zA-Z\/\-\_]+" - - if not isinstance(path, str): - raise InvalidResourceException(self.logical_id, "Basepath must be a string.") - - if re.search(invalid_regex, path) is not None: - raise InvalidResourceException(self.logical_id, "Invalid Basepath name provided.") - - logical_id = "{}{}{}".format(self.logical_id, re.sub(r"[\-_/]+", "", path), "ApiMapping") - basepath_mapping = ApiGatewayV2ApiMapping(logical_id, attributes=self.passthrough_resource_attributes) - basepath_mapping.DomainName = ref(api_domain_name) - basepath_mapping.ApiId = ref(http_api.logical_id) - basepath_mapping.Stage = ref(http_api.logical_id + ".Stage") - # ignore leading and trailing `/` in the path name - basepath_mapping.ApiMappingKey = path.strip("/") - basepath_resource_list.extend([basepath_mapping]) - return basepath_resource_list - - def _construct_record_sets_for_domain( - self, custom_domain_config: dict[str, Any], route53_config: dict[str, Any], api_domain_name: str - ) -> list[dict[str, Any]]: - recordset_list = [] - - recordset = {} - recordset["Name"] = custom_domain_config.get("DomainName") - recordset["Type"] = "A" - recordset["AliasTarget"] = self._construct_alias_target(custom_domain_config, route53_config, api_domain_name) - self._update_route53_routing_policy_properties(route53_config, recordset) - recordset_list.append(recordset) - - if route53_config.get("IpV6") is not None and route53_config.get("IpV6") is True: - recordset_ipv6 = {} - recordset_ipv6["Name"] = custom_domain_config.get("DomainName") - recordset_ipv6["Type"] = "AAAA" - recordset_ipv6["AliasTarget"] = self._construct_alias_target( - custom_domain_config, route53_config, api_domain_name - ) - self._update_route53_routing_policy_properties(route53_config, recordset_ipv6) - recordset_list.append(recordset_ipv6) - - return recordset_list - - @staticmethod - def _update_route53_routing_policy_properties(route53_config: dict[str, Any], recordset: dict[str, Any]) -> None: - if route53_config.get("Region") is not None: - recordset["Region"] = route53_config.get("Region") - if route53_config.get("SetIdentifier") is not None: - recordset["SetIdentifier"] = route53_config.get("SetIdentifier") - - def _construct_alias_target( - self, domain_config: dict[str, Any], route53_config: dict[str, Any], api_domain_name: str - ) -> dict[str, Any]: - alias_target = {} - target_health = route53_config.get("EvaluateTargetHealth") - - if target_health is not None: - alias_target["EvaluateTargetHealth"] = target_health - if domain_config.get("EndpointConfiguration") == "REGIONAL": - alias_target["HostedZoneId"] = fnGetAtt(api_domain_name, "RegionalHostedZoneId") - alias_target["DNSName"] = fnGetAtt(api_domain_name, "RegionalDomainName") - else: - raise InvalidResourceException( - self.logical_id, - "Only REGIONAL endpoint is supported on HTTP APIs.", - ) - return alias_target - def _add_auth(self) -> None: """ Add Auth configuration to the OAS file, if necessary @@ -515,7 +294,7 @@ def _add_tags(self) -> None: if not self.tags: self.tags = {} - self.tags[HttpApiTagName] = "SAM" + self.tags[self.default_tag_name] = "SAM" open_api_editor = OpenApiEditor(self.definition_body) @@ -523,31 +302,6 @@ def _add_tags(self) -> None: open_api_editor.add_tags(self.tags) self.definition_body = open_api_editor.openapi - def _get_permission( - self, authorizer_name: str, authorizer_lambda_function_arn: str, api_arn: str - ) -> LambdaPermission: - """Constructs and returns the Lambda Permission resource allowing the Authorizer to invoke the function. - - :returns: the permission resource - :rtype: model.lambda_.LambdaPermission - """ - - resource = "${__ApiId__}/authorizers/*" - source_arn = fnSub( - ArnGenerator.generate_arn(partition="${AWS::Partition}", service="execute-api", resource=resource), - {"__ApiId__": api_arn}, - ) - - lambda_permission = LambdaPermission( - self.logical_id + authorizer_name + "AuthorizerPermission", attributes=self.passthrough_resource_attributes - ) - lambda_permission.Action = "lambda:InvokeFunction" - lambda_permission.FunctionName = authorizer_lambda_function_arn - lambda_permission.Principal = "apigateway.amazonaws.com" - lambda_permission.SourceArn = source_arn - - return lambda_permission - def _construct_authorizer_lambda_permission(self, http_api: ApiGatewayV2HttpApi) -> list[LambdaPermission]: if not self.auth: return [] @@ -570,8 +324,10 @@ def _construct_authorizer_lambda_permission(self, http_api: ApiGatewayV2HttpApi) ): continue - permission = self._get_permission( - authorizer_name, authorizer.function_arn, http_api.get_runtime_attr("http_api_id") + permission = self._get_authorizer_permission( + self.logical_id + authorizer_name + "AuthorizerPermission", + authorizer.function_arn, + http_api.get_runtime_attr("http_api_id"), ) permissions.append(permission) diff --git a/samtranslator/model/api/websocket_api_generator.py b/samtranslator/model/api/websocket_api_generator.py new file mode 100644 index 0000000000..ff3d249c25 --- /dev/null +++ b/samtranslator/model/api/websocket_api_generator.py @@ -0,0 +1,400 @@ +from typing import Any + +from samtranslator.metrics.method_decorator import cw_timer +from samtranslator.model import Resource +from samtranslator.model.api.apiv2_generator import ApiV2Generator +from samtranslator.model.apigatewayv2 import ( + ApiGatewayV2Integration, + ApiGatewayV2Route, + ApiGatewayV2Stage, + ApiGatewayV2WebSocketApi, + ApiGatewayV2WSAuthorizer, +) +from samtranslator.model.exceptions import InvalidResourceException +from samtranslator.model.intrinsics import fnSub, is_intrinsic, ref +from samtranslator.model.lambda_ import LambdaPermission +from samtranslator.model.route53 import Route53RecordSetGroup +from samtranslator.utils.types import Intrinsicable + +# Different stage name from `$default` used by http, to avoid confusion with $default route and to avoid bugs +DefaultStageName = "default" +WebSocketApiTagName = "websocketapi:createdBy" + + +class AuthType: + NONE = "NONE" + AWS_IAM = "AWS_IAM" + CUSTOM = "CUSTOM" + TYPES = (NONE, AWS_IAM, CUSTOM) + + +class WebSocketApiGenerator(ApiV2Generator): + def __init__( # noqa: PLR0913 + self, + logical_id: str, + stage_name: str | None, + stage_variables: ( + dict[str, Intrinsicable[str]] | None + ), # I tried to keep presence of = None consistent with http + depends_on: list[str] | None, + name: str | None, + routes: dict[str, dict[str, Any]], + route_selection_expression: str, + api_key_selection_expression: Intrinsicable[str] | None = None, + access_log_settings: dict[str, Intrinsicable[str]] | None = None, + auth_config: dict[str, Any] | None = None, + default_route_settings: dict[str, Any] | None = None, + description: Intrinsicable[str] | None = None, + disable_execute_api_endpoint: Intrinsicable[bool] | None = None, + domain: dict[str, Any] | None = None, + disable_schema_validation: Intrinsicable[bool] | None = None, + ip_address_type: Intrinsicable[str] | None = None, + resource_attributes: dict[str, Intrinsicable[str]] | None = None, + passthrough_resource_attributes: dict[str, Intrinsicable[str]] | None = None, + route_settings: dict[str, Any] | None = None, + tags: dict[str, Intrinsicable[str]] | None = None, + ) -> None: + """Constructs an API Generator class that generates API Gateway resources + :param logical_id: Logical id of the SAM API Resource + :param stage_name: Name of the Stage + :param stage_variables: API Gateway Variables + :param depends_on: Any resources that need to be depended on + :param name: Name of the API Gateway "Api" resource + :param routes: Route Key, Function, and other config for routes + :param route_selection_expression: Used to determine method of selection routes + :param api_key_selection_expression: Selection expression for API keys + :param access_log_settings: Whether to send access logs and where for Stage + :param auth_config: Authorizer configuration + :param default_route_settings: DefaultRouteSettings on the stage + :param description: Description of the API Gateway resource + :param disable_execute_api_endpoint: DisableExecuteApiEndpoint property, to ensure that clients can access your API only by using a custom domain name + :param domain: domain configuration + :param disable_schema_validation: value of DisableSchemaValidation for the API + :param ip_address_type: "ipv4" or "dualstack" + :param resource_attributes: Resource attributes to add to API resources + :param passthrough_resource_attributes: Attributes such as 'Condition' that are added to derived resources + :param tags: Stage and API tags + """ + super().__init__( + logical_id, + stage_variables, + depends_on, + access_log_settings, + default_route_settings, + description, + disable_execute_api_endpoint, + domain, + passthrough_resource_attributes, + resource_attributes, + route_settings, + tags, + ) + # use logical id as name if none provided + self.name = name if name is not None else self.logical_id + self.stage_name = stage_name if stage_name is not None else DefaultStageName + self.stage_variables = stage_variables + self.routes = routes + if not self.routes: + raise InvalidResourceException(self.logical_id, "WebSocket API must have at least one route.") + self.route_selection_expression = route_selection_expression + self.api_key_selection_expression = api_key_selection_expression + self.auth_config = auth_config + self.default_tag_name = WebSocketApiTagName + self.description = description + self.disable_schema_validation = disable_schema_validation + self.ip_address_type = ip_address_type + if ( + self.ip_address_type is not None + and not is_intrinsic(self.ip_address_type) + and self.ip_address_type not in ("ipv4", "dualstack") + ): + raise InvalidResourceException(self.logical_id, "IpAddressType must be 'ipv4' or 'dualstack'.") + + # Validate that MTLS is not configured for WebSocket APIs + if domain and domain.get("MutualTlsAuthentication"): + raise InvalidResourceException( + self.logical_id, "Mutual TLS domain name association is not supported for Websocket APIs." + ) + + def _construct_websocket_api(self) -> ApiGatewayV2WebSocketApi: + websocket_api = ApiGatewayV2WebSocketApi( + self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes + ) + # Direct passes + websocket_api.ApiKeySelectionExpression = self.api_key_selection_expression + websocket_api.Description = self.description + websocket_api.DisableExecuteApiEndpoint = self.disable_execute_api_endpoint + websocket_api.DisableSchemaValidation = self.disable_schema_validation + websocket_api.IpAddressType = self.ip_address_type + if self.auth_config and "$connect" not in self.routes: + raise InvalidResourceException( + self.logical_id, "Authorization is only available if there is a $connect route." + ) + websocket_api.Name = self.name + websocket_api.RouteSelectionExpression = self.route_selection_expression + if not self.tags: + self.tags = {} + self.tags[self.default_tag_name] = "SAM" + websocket_api.Tags = self.tags + + # Static fields + websocket_api.ProtocolType = "WEBSOCKET" + return websocket_api + + def _construct_authorizer(self) -> ApiGatewayV2WSAuthorizer: + # generate logical id for resource + auth_name = self.logical_id + "ConnectAuthorizer" + auth = ApiGatewayV2WSAuthorizer(auth_name, attributes=self.passthrough_resource_attributes) + auth.ApiId = {"Ref": self.logical_id} + if self.auth_config: # unpacking + if "InvokeRole" in self.auth_config: + auth.AuthorizerCredentialsArn = self.auth_config["InvokeRole"] + auth.AuthorizerType = "REQUEST" + if "AuthArn" in self.auth_config: + auth.AuthorizerUri = fnSub( + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + {"AuthArn": self.auth_config["AuthArn"]}, + ) + auth.IdentitySource = self.auth_config.get("IdentitySource") + # use logical id if no name provided + if self.auth_config.get("Name"): + auth.Name = self.auth_config.get("Name") + else: + auth.Name = auth_name + return auth + + def _construct_authorizer_permission(self, websocket_api: ApiGatewayV2WebSocketApi) -> LambdaPermission | None: + """Constructs Lambda Permission allowing API Gateway to invoke the authorizer function. + Only needed when InvokeRole is not provided (resource-based permissions).""" + if not self.auth_config or self.auth_config.get("AuthType") != AuthType.CUSTOM: + return None + + # If InvokeRole is provided, API Gateway uses role-based invocation, no permission needed + if self.auth_config.get("InvokeRole"): + return None + + auth_arn = self.auth_config.get("AuthArn") + if not auth_arn: + return None + + return self._get_authorizer_permission( + self.logical_id + "AuthorizerPermission", + auth_arn, + websocket_api.get_runtime_attr("websocket_api_id"), + ) + + def _generate_route_resource_ids(self, route_key: str) -> tuple[str, str, str]: + """Convert route key to a valid CloudFormation logical ID component.""" + ROUTE_SUFFIX = "Route" + INTEGRATION_SUFFIX = "Integration" + PERMISSION_SUFFIX = "Permission" + + # Clean and validate the route key + clean_key = self._sanitize_route_key(route_key) + + # Generate IDs using a consistent pattern + base_id = f"{self.logical_id}{clean_key}" + return (f"{base_id}{ROUTE_SUFFIX}", f"{base_id}{INTEGRATION_SUFFIX}", f"{base_id}{PERMISSION_SUFFIX}") + + def _sanitize_route_key(self, route_key: str) -> str: + # Handle special WebSocket routes + special_routes = ["$connect", "$disconnect", "$default"] + if route_key in special_routes: + return route_key.replace("$", "").capitalize() + if route_key.isalnum(): + return route_key.capitalize() + raise InvalidResourceException( + self.logical_id, + f"Route key '{route_key}' must be alphanumeric. " + "Only $connect, $disconnect, and $default special routes are supported.", + ) + + def _validate_auth(self, auth_config: dict[str, Any]) -> None: + # Use parameter `auth_config` that we know is not None, instead of `self.auth_config` + auth_type = auth_config.get("AuthType") + if auth_type: + auth_type = auth_type.upper() + if auth_type not in AuthType.TYPES: + raise InvalidResourceException(self.logical_id, "AuthType is not one of AWS_IAM, CUSTOM or NONE.") + if auth_type == AuthType.CUSTOM and not auth_config.get("AuthArn"): + raise InvalidResourceException(self.logical_id, "AuthArn must be specified if AuthType is CUSTOM.") + if auth_type == AuthType.AWS_IAM and len(auth_config) > 1: + raise InvalidResourceException( + self.logical_id, "No additional configurations supported for AuthType AWS_IAM." + ) + if auth_type == AuthType.NONE and len(auth_config) > 1: + raise InvalidResourceException( + self.logical_id, "No additional configurations supported for AuthType NONE." + ) + else: + raise InvalidResourceException( + self.logical_id, "AuthType must be specified for additional auth configurations." + ) + + def _construct_route( + self, route_key: str, route_id: str, integration_id: str, route_spec: dict[str, Any] + ) -> ApiGatewayV2Route: + apigw_route = ApiGatewayV2Route(route_id, attributes=self.passthrough_resource_attributes) + apigw_route.RouteKey = route_key + apigw_route.ApiId = ref(self.logical_id) + apigw_route.ApiKeyRequired = route_spec.get("ApiKeyRequired") + apigw_route.ModelSelectionExpression = route_spec.get("ModelSelectionExpression") + apigw_route.OperationName = route_spec.get("OperationName") + apigw_route.RequestModels = route_spec.get("RequestModels") + if route_spec.get("RequestParameters"): + if route_key != "$connect": + raise InvalidResourceException( + self.logical_id, "Request parameters are only supported for the $connect route in WebSocket APIs." + ) + apigw_route.RequestParameters = route_spec.get("RequestParameters") + apigw_route.RouteResponseSelectionExpression = route_spec.get("RouteResponseSelectionExpression") + apigw_route.Target = {"Fn::Join": ["/", ["integrations", ref(integration_id)]]} + return apigw_route + + def _set_auth_type_and_return_custom_authorizer( + self, route_key: str, route: ApiGatewayV2Route + ) -> ApiGatewayV2WSAuthorizer | None: + if not self.auth_config: + return None + self._validate_auth(self.auth_config) + # set up auth if has config and has connect route + if route_key == "$connect": + if self.auth_config["AuthType"] == AuthType.CUSTOM: + if self.auth_config["AuthArn"]: # this is mostly to unpack the optional/for type checking purposes + apigw_authorizer = self._construct_authorizer() + route.AuthorizationType = AuthType.CUSTOM + route.AuthorizerId = {"Ref": apigw_authorizer.logical_id} + return apigw_authorizer + elif self.auth_config["AuthType"] == AuthType.AWS_IAM: + route.AuthorizationType = AuthType.AWS_IAM + else: + route.AuthorizationType = AuthType.NONE + return None + + def _construct_integration(self, apigw_integration_id: str, route_spec: dict[str, Any]) -> ApiGatewayV2Integration: + if "FunctionArn" not in route_spec: + raise InvalidResourceException(self.logical_id, "Route must have associated function.") + # set up integration + apigw_integration = ApiGatewayV2Integration( + apigw_integration_id, attributes=self.passthrough_resource_attributes + ) + apigw_integration.ApiId = ref(self.logical_id) + apigw_integration.IntegrationType = "AWS_PROXY" + apigw_integration.IntegrationUri = fnSub( + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + {"FunctionArn": route_spec["FunctionArn"]}, + ) + apigw_integration.TimeoutInMillis = route_spec.get("IntegrationTimeout") + return apigw_integration + + def _construct_permission(self, route_key: str, perms_id: str, route_spec: dict[str, Any]) -> LambdaPermission: + if "FunctionArn" not in route_spec: + raise InvalidResourceException(self.logical_id, "Route must have associated function.") + # set up permissions + perms = LambdaPermission(perms_id, attributes=self.passthrough_resource_attributes) + perms.Action = "lambda:InvokeFunction" + perms.FunctionName = route_spec["FunctionArn"] + perms.Principal = "apigateway.amazonaws.com" + perms.SourceArn = fnSub( + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${" + + self.logical_id + + ".ApiId}/" + + self.stage_name + + "/" + + route_key + ) + return perms + + def _construct_route_infr(self, route_key: str, route_spec: dict[str, Any]) -> tuple[ + ApiGatewayV2Route, + ApiGatewayV2Integration, + LambdaPermission, + ApiGatewayV2WSAuthorizer | None, + ]: + # set up names + apigw_route_id, apigw_integration_id, perms_id = self._generate_route_resource_ids(route_key) + # set up route + apigw_route = self._construct_route(route_key, apigw_route_id, apigw_integration_id, route_spec) + apigw_auth = self._set_auth_type_and_return_custom_authorizer(route_key, apigw_route) + apigw_integration = self._construct_integration(apigw_integration_id, route_spec) + permissions = self._construct_permission(route_key, perms_id, route_spec) + return apigw_route, apigw_integration, permissions, apigw_auth + + # Mostly taken from http + def _construct_stage(self) -> ApiGatewayV2Stage | None: + """Constructs and returns the ApiGatewayV2 Stage. + + :returns: the Stage to which this SAM Api corresponds + :rtype: model.apigatewayv2.ApiGatewayV2Stage + """ + # "Use default if no parameters passed" removed because default stage uses $default so we always need to at least change that + + # If StageName is some intrinsic function, then don't prefix the Stage's logical ID + # This will NOT create duplicates because we allow only ONE stage per API resource + if self.stage_name == "$default": + raise InvalidResourceException(self.logical_id, "Stages cannot be named $default for WebSocket APIs.") + stage_name_prefix = self.stage_name if isinstance(self.stage_name, str) else "" + # This is also altered in that the original checks for alphanumeric because the $ in $default would make that false + stage_logical_id = ( + self.logical_id + stage_name_prefix + "Stage" + if stage_name_prefix != DefaultStageName + else self.logical_id + "DefaultStage" + ) + # since this is no longer the API Gateway default stage exactly (that would be $default) I change it to be just DefaultStage + stage = ApiGatewayV2Stage(stage_logical_id, attributes=self.passthrough_resource_attributes) + stage.ApiId = ref(self.logical_id) + stage.StageName = self.stage_name + stage.StageVariables = self.stage_variables + stage.AccessLogSettings = self.access_log_settings + stage.DefaultRouteSettings = self.default_route_settings + stage.Tags = {self.default_tag_name: "SAM"} + stage.AutoDeploy = True + stage.RouteSettings = self.route_settings + + return stage + + @cw_timer(prefix="Generator", name="WebSocketApi") + def _to_cloudformation(self, route53_record_set_groups: dict[str, Route53RecordSetGroup]) -> list[Resource]: + """Generates CloudFormation resources from a SAM WebSocket API resource + + :returns: a tuple containing the WebSocketApi and Stage for an empty Api. + :rtype: tuple""" + websocket_api = self._construct_websocket_api() + domain, basepath_mapping, route53 = self._construct_api_domain(websocket_api, route53_record_set_groups) + stage = self._construct_stage() + + generated_resources_list: list[Resource] = [websocket_api] + + auth = None + route_logical_ids: list[str] = [] + for key, value in self.routes.items(): + apigw_route, apigw_integration, permission, apigw_auth = self._construct_route_infr(key, value) + # We keep all related route-integration-permission combos together + generated_resources_list.append(apigw_route) + generated_resources_list.append(apigw_integration) + generated_resources_list.append(permission) + route_logical_ids.append(apigw_route.logical_id) + + if apigw_auth: + auth = apigw_auth + + if domain: + generated_resources_list.append(domain) + if basepath_mapping: + generated_resources_list.extend(basepath_mapping) + if route53: + generated_resources_list.append(route53) + + if stage: + # Stage must depend on routes when RouteSettings references specific route keys + if self.route_settings and route_logical_ids: + stage.depends_on = route_logical_ids + generated_resources_list.append(stage) + + if auth: + generated_resources_list.append(auth) + auth_permission = self._construct_authorizer_permission(websocket_api) + if auth_permission: + generated_resources_list.append(auth_permission) + + return generated_resources_list diff --git a/samtranslator/model/apigatewayv2.py b/samtranslator/model/apigatewayv2.py index 7993c88809..fc5a31a852 100644 --- a/samtranslator/model/apigatewayv2.py +++ b/samtranslator/model/apigatewayv2.py @@ -11,8 +11,13 @@ APIGATEWAY_AUTHORIZER_KEY = "x-amazon-apigateway-authorizer" -class ApiGatewayV2HttpApi(Resource): +class ApiGatewayV2Api(Resource): resource_type = "AWS::ApiGatewayV2::Api" + property_types = {} + runtime_attrs = {} + + +class ApiGatewayV2HttpApi(ApiGatewayV2Api): property_types = { "Body": GeneratedProperty(), "BodyS3Location": GeneratedProperty(), @@ -37,6 +42,33 @@ def assign_tags(self, tags: dict[str, Any]) -> None: return +class ApiGatewayV2WebSocketApi(ApiGatewayV2Api): + property_types = { + "ApiKeySelectionExpression": GeneratedProperty(), + "Description": GeneratedProperty(), + "DisableExecuteApiEndpoint": GeneratedProperty(), + "DisableSchemaValidation": GeneratedProperty(), + "FailOnWarnings": GeneratedProperty(), + "IpAddressType": GeneratedProperty(), + "Name": GeneratedProperty(), + "ProtocolType": GeneratedProperty(), + "RouteSelectionExpression": GeneratedProperty(), + "Tags": GeneratedProperty(), + } + + runtime_attrs = {"websocket_api_id": lambda self: ref(self.logical_id)} + + def assign_tags(self, tags: dict[str, Any]) -> None: + """Overriding default 'assign_tags' function in Resource class + + Function to assign tags to the resource + :param tags: Tags to be assigned to the resource + + """ + if tags is not None and "Tags" in self.property_types: + self.Tags = tags + + class ApiGatewayV2Stage(Resource): resource_type = "AWS::ApiGatewayV2::Stage" property_types = { @@ -49,7 +81,7 @@ class ApiGatewayV2Stage(Resource): "StageName": GeneratedProperty(), "Tags": GeneratedProperty(), "StageVariables": GeneratedProperty(), - "AutoDeploy": GeneratedProperty(), + "AutoDeploy": GeneratedProperty(), # SAM sets this to true, which is why DeploymentId isn't here } runtime_attrs = {"stage_name": lambda self: ref(self.logical_id)} @@ -101,11 +133,56 @@ class ApiGatewayV2ApiMapping(Resource): } +class ApiGatewayV2Route(Resource): + resource_type = "AWS::ApiGatewayV2::Route" + property_types = { + "ApiId": GeneratedProperty(), + "ApiKeyRequired": GeneratedProperty(), # AuthorizationScopes not present because JWT not supported by WebSockets + "AuthorizationType": GeneratedProperty(), + "AuthorizerId": GeneratedProperty(), + "ModelSelectionExpression": GeneratedProperty(), + "OperationName": GeneratedProperty(), + "RequestModels": GeneratedProperty(), + "RequestParameters": GeneratedProperty(), + "RouteKey": GeneratedProperty(), + "RouteResponseSelectionExpression": GeneratedProperty(), + "Target": GeneratedProperty(), + } + + # https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-model-jwtconfiguration # Change to TypedDict when we don't have to support Python 3.7 JwtConfiguration = dict[str, Union[str, list[str]]] +class ApiGatewayV2Integration(Resource): + resource_type = "AWS::ApiGatewayV2::Integration" + property_types = { + "ApiId": GeneratedProperty(), + "IntegrationType": GeneratedProperty(), + "IntegrationUri": GeneratedProperty(), + "TimeoutInMillis": GeneratedProperty(), + } + + +class ApiGatewayV2WSAuthorizer(Resource): + """ + The ApiGatewayV2Authorizer was created for HTTP APIs and as a result turns the auth to part of the OpenAPI + definition, which WebSockets don't have. As a result, separate classes. + """ + + resource_type = "AWS::ApiGatewayV2::Authorizer" + property_types = { + "ApiId": GeneratedProperty(), + "AuthorizerCredentialsArn": GeneratedProperty(), + "AuthorizerPayloadFormatVersion": GeneratedProperty(), + "AuthorizerType": GeneratedProperty(), + "AuthorizerUri": GeneratedProperty(), + "IdentitySource": GeneratedProperty(), + "Name": GeneratedProperty(), + } + + class ApiGatewayV2Authorizer: def __init__( # type: ignore[no-untyped-def] # noqa: PLR0913 self, @@ -123,7 +200,7 @@ def __init__( # type: ignore[no-untyped-def] # noqa: PLR0913 enable_function_default_permissions=None, ): """ - Creates an authorizer for use in V2 Http Apis + Creates an authorizer for use in V2 Http Apis and WebSocket Apis """ self.api_logical_id = api_logical_id self.name = name diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 6d19d2cf5b..c1e35628fa 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -75,7 +75,10 @@ ApiGatewayUsagePlan, ApiGatewayUsagePlanKey, ) -from samtranslator.model.apigatewayv2 import ApiGatewayV2DomainName, ApiGatewayV2Stage +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 @@ -147,6 +150,7 @@ from .api.api_generator import ApiGenerator from .api.http_api_generator import HttpApiGenerator +from .api.websocket_api_generator import WebSocketApiGenerator from .packagetype import IMAGE, ZIP from .s3_utils.uri_parser import construct_image_code_object, construct_s3_location_object from .tags.resource_tagging import get_tag_list @@ -1873,6 +1877,106 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] if stage: resources.append(stage) + self.propagate_tags(resources, self.Tags, self.DefinitionBody is not None) + """ + HttpApi says in the documentation that tags supplied by the user via the Tags field will always be + added to DomainName and Stage resources as long as DefinitionBody is used over DefinitionUri. + Because there are the only two types of resources that HttpApi generates that have a tags field, PropagateTags + is functionally always true for DefinitionBody and always false for DefinitionUri. Adding these tags was originally + done in the constructors for these resources, but needed to be changed to accomodate WebSockets, which does not + add tags to these resources by default. + """ + + return resources + + +class SamWebSocketApi(SamResourceMacro): + """SAM WebSocket API Macro""" + + resource_type = "AWS::Serverless::WebSocketApi" + property_types = { + "ApiKeySelectionExpression": PropertyType(False, IS_STR), + "AccessLogSettings": PropertyType(False, IS_DICT), + "Auth": PropertyType(False, IS_DICT), + "DefaultRouteSettings": PropertyType(False, IS_DICT), + "Description": PropertyType(False, IS_STR), + "DisableExecuteApiEndpoint": PropertyType(False, IS_BOOL), + "Domain": PropertyType(False, IS_DICT), + "DisableSchemaValidation": PropertyType(False, IS_BOOL), + "FailOnWarnings": PropertyType(False, IS_BOOL), + "IpAddressType": PropertyType(False, IS_STR), + "Name": PropertyType(False, IS_STR), + "PropagateTags": PropertyType(False, IS_BOOL), + "Routes": PropertyType(True, IS_DICT), + "RouteSettings": PropertyType(False, IS_DICT), + "RouteSelectionExpression": PropertyType(True, IS_STR), + "StageName": PropertyType(False, IS_STR), + "StageVariables": PropertyType(False, IS_DICT), + "Tags": PropertyType(False, IS_DICT), + } + + ApiKeySelectionExpression: Intrinsicable[str] | None + AccessLogSettings: dict[str, Any] | None + Auth: dict[str, Any] | None + DefaultRouteSettings: dict[str, Any] | None + Description: Intrinsicable[str] | None + DisableExecuteApiEndpoint: Intrinsicable[bool] | None + DisableSchemaValidation: Intrinsicable[bool] | None + Domain: dict[str, Any] | None + FailOnWarnings: Intrinsicable[bool] | None + IpAddressType: Intrinsicable[str] | None + Name: str | None + PropagateTags: bool | None + Routes: dict[str, dict[str, Any]] + RouteSettings: dict[str, Any] | None + RouteSelectionExpression: str + StageName: str | None + StageVariables: dict[str, Intrinsicable[str]] | None + Tags: dict[str, Any] | None + + referable_properties = { + "Stage": ApiGatewayV2Stage.resource_type, + "DomainName": ApiGatewayV2DomainName.resource_type, + } + + @cw_timer + def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] + """Returns the API GatewayV2 Api, Deployment, Stage, Routes, Integrations, and Permissions to which this SAM Api corresponds. + + :param dict kwargs: already-converted resources that may need to be modified when converting this \ + macro to pure CloudFormation + :returns: a list of vanilla CloudFormation Resources, to which this function expands + :rtype: list + """ + self.validate_properties() + intrinsics_resolver = kwargs["intrinsics_resolver"] + self.Auth = intrinsics_resolver.resolve_parameter_refs(self.Auth) + self.Domain = intrinsics_resolver.resolve_parameter_refs(self.Domain) + self.Routes = intrinsics_resolver.resolve_parameter_refs(self.Routes) + + api_generator = WebSocketApiGenerator( + logical_id=self.logical_id, + stage_variables=self.StageVariables, + depends_on=self.depends_on, + name=self.Name, + stage_name=self.StageName, + api_key_selection_expression=self.ApiKeySelectionExpression, + access_log_settings=self.AccessLogSettings, + auth_config=self.Auth, + default_route_settings=self.DefaultRouteSettings, + description=self.Description, + disable_execute_api_endpoint=self.DisableExecuteApiEndpoint, + disable_schema_validation=self.DisableSchemaValidation, + domain=self.Domain, + ip_address_type=self.IpAddressType, + routes=self.Routes, + route_settings=self.RouteSettings, + route_selection_expression=self.RouteSelectionExpression, + tags=self.Tags, + ) + + resources: list[Resource] = api_generator._to_cloudformation(kwargs.get("route53setrecordgroups", {})) + self.propagate_tags(resources, self.Tags, self.PropagateTags) return resources diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 225b14372d..83940b03e4 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -115,11 +115,27 @@ class Globals: "KmsKeyArn", "PropagateTags", ], + SamResourceType.WebSocketApi.value: [ + "AccessLogSettings", + "ApiKeySelectionExpression", + "DefaultRouteSettings", + "DisableExecuteApiEndpoint", + "DisableSchemaValidation", + "Domain", + "FailOnWarnings", + "IpAddressType", + "PropagateTags", + "RouteSelectionExpression", + "RouteSettings", + "StageVariables", + "Tags", + ], } # unreleased_properties *must be* part of supported_properties too unreleased_properties: dict[str, list[str]] = { SamResourceType.Function.value: [], } + unreleased_resource_types: list[str] = [] def __init__(self, template: dict[str, Any]) -> None: diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index f20e7cb81f..61f31b7b0c 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -362703,6 +362703,67 @@ "title": "ApiKey", "type": "object" }, + "AuthConfig": { + "additionalProperties": false, + "properties": { + "AuthArn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "AuthArn" + }, + "AuthType": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AuthType" + }, + "IdentitySource": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IdentitySource" + }, + "InvokeRole": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "InvokeRole" + }, + "Name": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "Name" + } + }, + "required": [ + "AuthType" + ], + "title": "AuthConfig", + "type": "object" + }, "Authorizer": { "additionalProperties": false, "properties": { @@ -366629,6 +366690,91 @@ "title": "VpcConfig", "type": "object" }, + "WebSocketApiRoute": { + "additionalProperties": false, + "properties": { + "ApiKeyRequired": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ApiKeyRequired" + }, + "FunctionArn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "FunctionArn" + }, + "IntegrationTimeout": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IntegrationTimeout" + }, + "ModelSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ModelSelectionExpression" + }, + "OperationName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "OperationName" + }, + "RequestModels": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RequestModels" + }, + "RequestParameters": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RequestParameters" + }, + "RouteResponseSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteResponseSelectionExpression" + } + }, + "required": [ + "FunctionArn" + ], + "title": "WebSocketApiRoute", + "type": "object" + }, "__main____Globals": { "additionalProperties": false, "properties": { @@ -366652,6 +366798,9 @@ }, "StateMachine": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_statemachine__Globals" + }, + "WebSocketApi": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Globals" } }, "title": "Globals", @@ -369691,7 +369840,7 @@ "items": { "type": "string" }, - "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name. \n*Type*: List \n*Required*: No \n*Default*: / \n*CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property.", + "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name\\. \n*Type*: List \n*Required*: No \n*Default*: / \n*AWS CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource\\. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property\\.", "title": "BasePath", "type": "array" }, @@ -369701,7 +369850,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The Amazon Resource Name (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/ARN.html) of an AWS managed certificate for this domain name's endpoint. AWS Certificate Manager is the only supported source. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource.", + "markdownDescription": "The Amazon Resource Name \\(ARN\\) of an AWS managed certificate for this domain name's endpoint\\. AWS Certificate Manager is the only supported source\\. \n*Type*: String \n*Required*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource\\.", "title": "CertificateArn" }, "DomainName": { @@ -369710,7 +369859,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The custom domain name for your API Gateway API. Uppercase letters are not supported. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name). For information about generated CloudFormation resources, see [Generated 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*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource.", + "markdownDescription": "The custom domain name for your API Gateway API\\. Uppercase letters are not supported\\. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set\\. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name)\\. For 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*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource\\.", "title": "DomainName" }, "EndpointConfiguration": { @@ -369725,7 +369874,7 @@ "type": "string" } ], - "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain. The value of this property determines how the `CertificateArn` property is mapped in CloudFormation. \nThe only valid value for HTTP APIs is `REGIONAL`. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain\\. The value of this property determines how the `CertificateArn` property is mapped in AWS CloudFormation\\. \nThe only valid value for HTTP APIs is `REGIONAL`\\. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "EndpointConfiguration" }, "MutualTlsAuthentication": { @@ -369734,7 +369883,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The mutual transport layer security (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/TLS.html) authentication configuration for a custom domain name. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource.", + "markdownDescription": "The mutual transport layer security \\(TLS\\) authentication configuration for a custom domain name\\. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource\\.", "title": "MutualTlsAuthentication" }, "OwnershipVerificationCertificateArn": { @@ -369743,7 +369892,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type.", + "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain\\. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", "title": "OwnershipVerificationCertificateArn" }, "Route53": { @@ -369752,7 +369901,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Route53" } ], - "markdownDescription": "Defines an Amazon Route\u00a053 configuration. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Route53" }, "SecurityPolicy": { @@ -369761,7 +369910,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The TLS version of the security policy for this domain name. \nThe only valid value for HTTP APIs is `TLS_1_2`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type.", + "markdownDescription": "The TLS version of the security policy for this domain name\\. \nThe only valid value for HTTP APIs is `TLS_1_2`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", "title": "SecurityPolicy" } }, @@ -369781,7 +369930,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The settings for access logging in a stage. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The settings for access logging in a stage\\. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "AccessLogSettings" }, "Auth": { @@ -369790,7 +369939,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Auth" } ], - "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API\\. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*\\. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Auth" }, "CorsConfiguration": { @@ -369799,7 +369948,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Manages cross-origin resource sharing (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html) for all your API Gateway HTTP APIs. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object. Note that https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html requires AWS SAM to modify your OpenAPI definition, so https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html works only if the `DefinitionBody` property is specified. \nFor more information, see [Configuring https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence. If this property is set to `true`, then all origins are allowed.\n*Type*: String \\$1 [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Manages cross\\-origin resource sharing \\(CORS\\) for all your API Gateway HTTP APIs\\. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object\\. Note that CORS requires AWS SAM to modify your OpenAPI definition, so CORS works only if the `DefinitionBody` property is specified\\. \nFor more information, see [Configuring CORS for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*\\. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence\\. If this property is set to `true`, then all origins are allowed\\.\n*Type*: String \\| [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "CorsConfiguration" }, "DefaultRouteSettings": { @@ -369808,7 +369957,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The default route settings for this HTTP API. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The default route settings for this HTTP API\\. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "DefaultRouteSettings" }, "Domain": { @@ -369817,7 +369966,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Domain" } ], - "markdownDescription": "Configures a custom domain for this API Gateway HTTP API. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures a custom domain for this API Gateway HTTP API\\. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Domain" }, "FailOnWarnings": { @@ -369826,11 +369975,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether to roll back the HTTP API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "FailOnWarnings" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.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" }, @@ -369840,7 +369989,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The route settings, per route, for this HTTP API. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The route settings, per route, for this HTTP API\\. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "RouteSettings" }, "StageVariables": { @@ -369849,11 +369998,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "A map that defines the stage variables. Variable names can have alphanumeric and underscore characters. The values must match [A-Za-z0-9-.\\$1\\$1:/?\\$1&=,]\\$1. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "A map that defines the stage variables\\. Variable names can have alphanumeric and underscore characters\\. The values must match \\[A\\-Za\\-z0\\-9\\-\\.\\_\\~:/?\\#&=,\\]\\+\\. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageVariables" }, "Tags": { - "markdownDescription": "A map (string to string) that specifies the tags to add to this API Gateway stage. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`. Values can be 1 to 256 Unicode characters in length. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource (if `DomainName` is specified).", + "markdownDescription": "A map \\(string to string\\) that specifies the tags to add to this API Gateway stage\\. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`\\. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`\\. Values can be 1 to 256 Unicode characters in length\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified\\. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag\\. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource \\(if `DomainName` is specified\\)\\.", "title": "Tags", "type": "object" } @@ -369870,7 +370019,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The settings for access logging in a stage. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The settings for access logging in a stage\\. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "AccessLogSettings" }, "Auth": { @@ -369879,7 +370028,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Auth" } ], - "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API\\. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*\\. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Auth" }, "CorsConfiguration": { @@ -369888,7 +370037,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Manages cross-origin resource sharing (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html) for all your API Gateway HTTP APIs. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object. Note that https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html requires AWS SAM to modify your OpenAPI definition, so https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html works only if the `DefinitionBody` property is specified. \nFor more information, see [Configuring https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence. If this property is set to `true`, then all origins are allowed.\n*Type*: String \\$1 [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Manages cross\\-origin resource sharing \\(CORS\\) for all your API Gateway HTTP APIs\\. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object\\. Note that CORS requires AWS SAM to modify your OpenAPI definition, so CORS works only if the `DefinitionBody` property is specified\\. \nFor more information, see [Configuring CORS for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*\\. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence\\. If this property is set to `true`, then all origins are allowed\\.\n*Type*: String \\| [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "CorsConfiguration" }, "DefaultRouteSettings": { @@ -369897,11 +370046,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The default route settings for this HTTP API. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The default route settings for this HTTP API\\. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "DefaultRouteSettings" }, "DefinitionBody": { - "markdownDescription": "The OpenAPI definition that describes your HTTP API. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \n*Type*: JSON \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to CloudFormation. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource.", + "markdownDescription": "The OpenAPI definition that describes your HTTP API\\. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \n*Type*: JSON \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource\\. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to AWS CloudFormation\\. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource\\.", "title": "DefinitionBody", "type": "object" }, @@ -369914,11 +370063,11 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__DefinitionUri" } ], - "markdownDescription": "The Amazon Simple Storage Service (Amazon S3) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API. The Amazon S3 object that this property references must be a valid OpenAPI definition file. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html). \n*Type*: String \\$1 [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource. The nested Amazon S3 properties are named differently.", + "markdownDescription": "The Amazon Simple Storage Service \\(Amazon S3\\) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API\\. The Amazon S3 object that this property references must be a valid OpenAPI definition file\\. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly\\. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`\\. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html)\\. \n*Type*: String \\| [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource\\. The nested Amazon S3 properties are named differently\\.", "title": "DefinitionUri" }, "Description": { - "markdownDescription": "The description of the HTTP API resource. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The description of the HTTP API resource\\. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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": "Description", "type": "string" }, @@ -369928,7 +370077,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`. By default, clients can invoke your API with the default endpoint. To require that clients only use a custom domain name to invoke your API, disable the default endpoint. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x-amazon-apigateway-endpoint-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`\\. By default, clients can invoke your API with the default endpoint\\. To require that clients only use a custom domain name to invoke your API, disable the default endpoint\\. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource\\. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x\\-amazon\\-apigateway\\-endpoint\\-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "DisableExecuteApiEndpoint" }, "Domain": { @@ -369937,7 +370086,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Domain" } ], - "markdownDescription": "Configures a custom domain for this API Gateway HTTP API. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures a custom domain for this API Gateway HTTP API\\. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Domain" }, "FailOnWarnings": { @@ -369946,7 +370095,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether to roll back the HTTP API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "FailOnWarnings" }, "Name": { @@ -369955,11 +370104,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the HTTP API resource. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The name of the HTTP API resource\\. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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": "Name" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.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" }, @@ -369969,7 +370118,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The route settings, per route, for this HTTP API. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The route settings, per route, for this HTTP API\\. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "RouteSettings" }, "StageName": { @@ -369978,7 +370127,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the API stage. If no name is specified, AWS SAM uses the `$default` stage from API Gateway. \n*Type*: String \n*Required*: No \n*Default*: \\$1default \n*CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The name of the API stage\\. If no name is specified, AWS SAM uses the `$default` stage from API Gateway\\. \n*Type*: String \n*Required*: No \n*Default*: $default \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageName" }, "StageVariables": { @@ -369987,11 +370136,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "A map that defines the stage variables. Variable names can have alphanumeric and underscore characters. The values must match [A-Za-z0-9-.\\$1\\$1:/?\\$1&=,]\\$1. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "A map that defines the stage variables\\. Variable names can have alphanumeric and underscore characters\\. The values must match \\[A\\-Za\\-z0\\-9\\-\\.\\_\\~:/?\\#&=,\\]\\+\\. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageVariables" }, "Tags": { - "markdownDescription": "A map (string to string) that specifies the tags to add to this API Gateway stage. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`. Values can be 1 to 256 Unicode characters in length. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource (if `DomainName` is specified).", + "markdownDescription": "A map \\(string to string\\) that specifies the tags to add to this API Gateway stage\\. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`\\. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`\\. Values can be 1 to 256 Unicode characters in length\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified\\. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag\\. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource \\(if `DomainName` is specified\\)\\.", "title": "Tags", "type": "object" } @@ -370064,7 +370213,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Configures a custom distribution of the API custom domain name. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution. \n*CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html).", + "markdownDescription": "Configures a custom distribution of the API custom domain name\\. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution\\. \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html)\\.", "title": "DistributionDomainName" }, "EvaluateTargetHealth": { @@ -370073,7 +370222,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution.", + "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution\\.", "title": "EvaluateTargetHealth" }, "HostedZoneId": { @@ -370082,7 +370231,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ID of the hosted zone that you want to create records in. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", + "markdownDescription": "The ID of the hosted zone that you want to create records in\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", "title": "HostedZoneId" }, "HostedZoneName": { @@ -370091,23 +370240,31 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the hosted zone that you want to create records in. You must include a trailing dot (for example, `www.example.com.`) as part of the `HostedZoneName`. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", + "markdownDescription": "The name of the hosted zone that you want to create records in\\. You must include a trailing dot \\(for example, `www.example.com.`\\) as part of the `HostedZoneName`\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", "title": "HostedZoneName" }, "IpV6": { - "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone\\. \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\\.", "title": "IpV6", "type": "boolean" }, "Region": { - "markdownDescription": "*Latency-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region. Route\u00a053 then returns the value that is associated with the selected resource record set. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set.\n+ You can only create one latency resource record set for each Amazon EC2 Region.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for.\n+ You can't create non-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type.", - "title": "Region", - "type": "string" + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Latency\\-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to\\. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type\\. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region\\. Route\u00a053 then returns the value that is associated with the selected resource record set\\. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set\\.\n+ You can only create one latency resource record set for each Amazon EC2 Region\\.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions\\. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for\\.\n+ You can't create non\\-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "Region" }, "SetIdentifier": { - "markdownDescription": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme.example.com that have a type of A. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type.", - "title": "SetIdentifier", - "type": "string" + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme\\.example\\.com that have a type of A\\. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set\\. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "SetIdentifier" } }, "title": "Route53", @@ -370702,7 +370859,7 @@ "additionalProperties": false, "properties": { "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.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" } @@ -370717,12 +370874,12 @@ "$ref": "#/definitions/PassThroughProp" }, "Definition": { - "markdownDescription": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples). \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: Map \n*Required*: Conditional \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML\\. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples)\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: Map \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Definition", "type": "object" }, "DefinitionSubstitutions": { - "markdownDescription": "A string-to-string map that specifies the mappings for placeholder variables in the state machine definition. This enables you to inject values obtained at runtime (for example, from intrinsic functions) into the state machine definition. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition.", + "markdownDescription": "A string\\-to\\-string map that specifies the mappings for placeholder variables in the state machine definition\\. This enables you to inject values obtained at runtime \\(for example, from intrinsic functions\\) into the state machine definition\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource\\. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition\\.", "title": "DefinitionSubstitutions", "type": "object" }, @@ -370735,7 +370892,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The Amazon Simple Storage Service (Amazon S3) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition. To do this, you must use version 0.52.0 or later of the AWS SAM CLI. \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: String \\$1 [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The Amazon Simple Storage Service \\(Amazon S3\\) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition\\. To do this, you must use version 0\\.52\\.0 or later of the AWS SAM CLI\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: String \\| [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "DefinitionUri" }, "DeploymentPreference": { @@ -370761,7 +370918,7 @@ } ] }, - "markdownDescription": "Specifies the events that trigger this state machine. Events consist of a type and a set of properties that depend on the type. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Specifies the events that trigger this state machine\\. Events consist of a type and a set of properties that depend on the type\\. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Events", "type": "object" }, @@ -370771,7 +370928,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Defines which execution history events are logged and where they are logged. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "Defines which execution history events are logged and where they are logged\\. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Logging" }, "Name": { @@ -370780,7 +370937,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the state machine. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The name of the state machine\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Name" }, "PermissionsBoundary": { @@ -370789,7 +370946,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of a permissions boundary to use for this state machine's execution role. This property only works if the role is generated for you. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource.", + "markdownDescription": "The ARN of a permissions boundary to use for this state machine's execution role\\. This property only works if the role is generated for you\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource\\.", "title": "PermissionsBoundary" }, "Policies": { @@ -370814,11 +370971,11 @@ "type": "array" } ], - "markdownDescription": "Permission policies for this state machine. Policies will be appended to the state machine's default AWS Identity and Access Management (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html) 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/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) or [customer managed policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 \\$1 List \\$1 Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Permission policies for this state machine\\. Policies will be appended to the state machine'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 unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Policies" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.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" }, @@ -370828,7 +370985,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of an IAM role to use as this state machine's execution role. \n*Type*: String \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The ARN of an IAM role to use as this state machine's execution role\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Role" }, "RolePath": { @@ -370837,11 +370994,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The path to the state machine'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*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.", + "markdownDescription": "The path to the state machine'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\\.", "title": "RolePath" }, "Tags": { - "markdownDescription": "A string-to-string map that specifies the tags added to the state machine and the corresponding execution role. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it.", + "markdownDescription": "A string\\-to\\-string map that specifies the tags added to the state machine and the corresponding execution role\\. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource\\. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it\\.", "title": "Tags", "type": "object" }, @@ -370851,7 +371008,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Selects whether or not AWS X-Ray is enabled for the state machine. For more information about using X-Ray with Step Functions, see [AWS X-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "Selects whether or not AWS X\\-Ray is enabled for the state machine\\. For more information about using X\\-Ray with Step Functions, see [AWS X\\-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*\\. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Tracing" }, "Type": { @@ -370860,7 +371017,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The type of the state machine. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The type of the state machine\\. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Type" }, "UseAliasAsEventTarget": { @@ -371302,6 +371459,434 @@ }, "title": "ScheduleV2EventProperties", "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain": { + "additionalProperties": false, + "properties": { + "BasePath": { + "items": { + "type": "string" + }, + "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name\\. \n*Type*: List \n*Required*: No \n*Default*: / \n*AWS CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource\\. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property\\.", + "title": "BasePath", + "type": "array" + }, + "CertificateArn": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The Amazon Resource Name \\(ARN\\) of an AWS managed certificate for this domain name's endpoint\\. AWS Certificate Manager is the only supported source\\. \n*Type*: String \n*Required*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource\\.", + "title": "CertificateArn" + }, + "DomainName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The custom domain name for your API Gateway API\\. Uppercase letters are not supported\\. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set\\. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name)\\. For 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*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource\\.", + "title": "DomainName" + }, + "EndpointConfiguration": { + "anyOf": [ + { + "type": "object" + }, + { + "enum": [ + "REGIONAL" + ], + "type": "string" + } + ], + "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain\\. The value of this property determines how the `CertificateArn` property is mapped in AWS CloudFormation\\. \nThe only valid value for HTTP APIs is `REGIONAL`\\. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "EndpointConfiguration" + }, + "MutualTlsAuthentication": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The mutual transport layer security \\(TLS\\) authentication configuration for a custom domain name\\. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource\\.", + "title": "MutualTlsAuthentication" + }, + "OwnershipVerificationCertificateArn": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain\\. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", + "title": "OwnershipVerificationCertificateArn" + }, + "Route53": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Route53" + } + ], + "markdownDescription": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "Route53" + }, + "SecurityPolicy": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The TLS version of the security policy for this domain name\\. \nThe only valid value for HTTP APIs is `TLS_1_2`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", + "title": "SecurityPolicy" + } + }, + "required": [ + "CertificateArn", + "DomainName" + ], + "title": "Domain", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Globals": { + "additionalProperties": false, + "properties": { + "AccessLogSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AccessLogSettings" + }, + "ApiKeySelectionExpression": { + "markdownDescription": "TODO", + "title": "ApiKeySelectionExpression", + "type": "string" + }, + "DefaultRouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DefaultRouteSettings" + }, + "DisableExecuteApiEndpoint": { + "markdownDescription": "TODO", + "title": "DisableExecuteApiEndpoint", + "type": "boolean" + }, + "DisableSchemaValidation": { + "markdownDescription": "TODO", + "title": "DisableSchemaValidation", + "type": "boolean" + }, + "Domain": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain" + } + ], + "markdownDescription": "TODO", + "title": "Domain" + }, + "IpAddressType": { + "markdownDescription": "TODO", + "title": "IpAddressType", + "type": "string" + }, + "PropagateTags": { + "markdownDescription": "TODO", + "title": "PropagateTags", + "type": "boolean" + }, + "RouteSelectionExpression": { + "markdownDescription": "TODO", + "title": "RouteSelectionExpression", + "type": "string" + }, + "RouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSettings" + }, + "StageVariables": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageVariables" + }, + "Tags": { + "markdownDescription": "TODO", + "title": "Tags", + "type": "object" + } + }, + "title": "Globals", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Properties": { + "additionalProperties": false, + "properties": { + "AccessLogSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AccessLogSettings" + }, + "ApiKeySelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ApiKeySelectionExpression" + }, + "Auth": { + "allOf": [ + { + "$ref": "#/definitions/AuthConfig" + } + ], + "markdownDescription": "TODO", + "title": "Auth" + }, + "DefaultRouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DefaultRouteSettings" + }, + "Description": { + "markdownDescription": "TODO", + "title": "Description", + "type": "string" + }, + "DisableExecuteApiEndpoint": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DisableExecuteApiEndpoint" + }, + "DisableSchemaValidation": { + "markdownDescription": "TODO", + "title": "DisableSchemaValidation", + "type": "boolean" + }, + "Domain": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain" + } + ], + "markdownDescription": "TODO", + "title": "Domain" + }, + "IpAddressType": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IpAddressType" + }, + "Name": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "Name" + }, + "PropagateTags": { + "markdownDescription": "TODO", + "title": "PropagateTags", + "type": "boolean" + }, + "RouteSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSelectionExpression" + }, + "RouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSettings" + }, + "Routes": { + "additionalProperties": { + "$ref": "#/definitions/WebSocketApiRoute" + }, + "markdownDescription": "TODO", + "title": "Routes", + "type": "object" + }, + "StageName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageName" + }, + "StageVariables": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageVariables" + }, + "Tags": { + "markdownDescription": "TODO", + "title": "Tags", + "type": "object" + } + }, + "required": [ + "Routes", + "RouteSelectionExpression" + ], + "title": "Properties", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__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_websocketapi__Properties" + }, + "Type": { + "enum": [ + "AWS::Serverless::WebSocketApi" + ], + "title": "Type", + "type": "string" + }, + "UpdateReplacePolicy": { + "$ref": "#/definitions/PassThroughProp" + } + }, + "required": [ + "Type" + ], + "title": "Resource", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Route53": { + "additionalProperties": false, + "properties": { + "EvaluateTargetHealth": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution\\.", + "title": "EvaluateTargetHealth" + }, + "HostedZoneId": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ID of the hosted zone that you want to create records in\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "title": "HostedZoneId" + }, + "HostedZoneName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The name of the hosted zone that you want to create records in\\. You must include a trailing dot \\(for example, `www.example.com.`\\) as part of the `HostedZoneName`\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "title": "HostedZoneName" + }, + "IpV6": { + "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone\\. \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\\.", + "title": "IpV6", + "type": "boolean" + }, + "Region": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Latency\\-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to\\. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type\\. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region\\. Route\u00a053 then returns the value that is associated with the selected resource record set\\. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set\\.\n+ You can only create one latency resource record set for each Amazon EC2 Region\\.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions\\. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for\\.\n+ You can't create non\\-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "Region" + }, + "SetIdentifier": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme\\.example\\.com that have a type of A\\. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set\\. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "SetIdentifier" + } + }, + "title": "Route53", + "type": "object" } }, "properties": { @@ -371385,6 +371970,9 @@ { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Resource" }, + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Resource" + }, { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_application__Resource" }, diff --git a/samtranslator/sdk/resource.py b/samtranslator/sdk/resource.py index d2b0a24a7f..4197a65d55 100644 --- a/samtranslator/sdk/resource.py +++ b/samtranslator/sdk/resource.py @@ -68,6 +68,7 @@ class SamResourceType(Enum): Application = "AWS::Serverless::Application" LambdaLayerVersion = "AWS::Serverless::LayerVersion" HttpApi = "AWS::Serverless::HttpApi" + WebSocketApi = "AWS::Serverless::WebSocketApi" StateMachine = "AWS::Serverless::StateMachine" CapacityProvider = "AWS::Serverless::CapacityProvider" diff --git a/samtranslator/translator/translator.py b/samtranslator/translator/translator.py index 6df0164051..a34d9830ed 100644 --- a/samtranslator/translator/translator.py +++ b/samtranslator/translator/translator.py @@ -284,7 +284,11 @@ def _get_resources_to_iterate( functions.append(data) elif resource["Type"] == "AWS::Serverless::StateMachine": statemachines.append(data) - elif resource["Type"] in ("AWS::Serverless::Api", "AWS::Serverless::HttpApi"): + elif resource["Type"] in ( + "AWS::Serverless::Api", + "AWS::Serverless::HttpApi", + "AWS::Serverless::WebSocketApi", + ): apis.append(data) elif resource["Type"] == "AWS::Serverless::Connector": connectors.append(data) diff --git a/samtranslator/translator/verify_logical_id.py b/samtranslator/translator/verify_logical_id.py index 7c52634da3..89177ea241 100644 --- a/samtranslator/translator/verify_logical_id.py +++ b/samtranslator/translator/verify_logical_id.py @@ -8,7 +8,7 @@ "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::ApiGatewayV2::Api": ["AWS::Serverless::HttpApi", "AWS::Serverless::WebSocketApi"], "AWS::S3::Bucket": "AWS::S3::Bucket", "AWS::SNS::Topic": "AWS::SNS::Topic", "AWS::DynamoDB::Table": "AWS::Serverless::SimpleTable", diff --git a/samtranslator/validator/sam_schema/schema_new.json b/samtranslator/validator/sam_schema/schema_new.json index 1b55fdbe30..65bca0b8b4 100644 --- a/samtranslator/validator/sam_schema/schema_new.json +++ b/samtranslator/validator/sam_schema/schema_new.json @@ -107,6 +107,7 @@ "AWS::Serverless::Application", "AWS::Serverless::Function", "AWS::Serverless::HttpApi", + "AWS::Serverless::WebSocketApi", "AWS::Serverless::LayerVersion", "AWS::Serverless::SimpleTable", "AWS::Serverless::StateMachine", diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 9eebf28b6f..ffc0b7b668 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -154,6 +154,67 @@ "title": "ApiKey", "type": "object" }, + "AuthConfig": { + "additionalProperties": false, + "properties": { + "AuthArn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "AuthArn" + }, + "AuthType": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AuthType" + }, + "IdentitySource": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IdentitySource" + }, + "InvokeRole": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "InvokeRole" + }, + "Name": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "Name" + } + }, + "required": [ + "AuthType" + ], + "title": "AuthConfig", + "type": "object" + }, "Authorizer": { "additionalProperties": false, "properties": { @@ -4172,6 +4233,91 @@ "title": "VpcConfig", "type": "object" }, + "WebSocketApiRoute": { + "additionalProperties": false, + "properties": { + "ApiKeyRequired": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ApiKeyRequired" + }, + "FunctionArn": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ], + "markdownDescription": "TODO", + "title": "FunctionArn" + }, + "IntegrationTimeout": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IntegrationTimeout" + }, + "ModelSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ModelSelectionExpression" + }, + "OperationName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "OperationName" + }, + "RequestModels": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RequestModels" + }, + "RequestParameters": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RequestParameters" + }, + "RouteResponseSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteResponseSelectionExpression" + } + }, + "required": [ + "FunctionArn" + ], + "title": "WebSocketApiRoute", + "type": "object" + }, "__main____Globals": { "additionalProperties": false, "properties": { @@ -4195,6 +4341,9 @@ }, "StateMachine": { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_statemachine__Globals" + }, + "WebSocketApi": { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Globals" } }, "title": "Globals", @@ -8364,7 +8513,7 @@ "items": { "type": "string" }, - "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name. \n*Type*: List \n*Required*: No \n*Default*: / \n*CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property.", + "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name\\. \n*Type*: List \n*Required*: No \n*Default*: / \n*AWS CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource\\. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property\\.", "title": "BasePath", "type": "array" }, @@ -8374,7 +8523,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The Amazon Resource Name (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/ARN.html) of an AWS managed certificate for this domain name's endpoint. AWS Certificate Manager is the only supported source. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource.", + "markdownDescription": "The Amazon Resource Name \\(ARN\\) of an AWS managed certificate for this domain name's endpoint\\. AWS Certificate Manager is the only supported source\\. \n*Type*: String \n*Required*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource\\.", "title": "CertificateArn" }, "DomainName": { @@ -8383,7 +8532,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The custom domain name for your API Gateway API. Uppercase letters are not supported. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name). For information about generated CloudFormation resources, see [Generated 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*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource.", + "markdownDescription": "The custom domain name for your API Gateway API\\. Uppercase letters are not supported\\. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set\\. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name)\\. For 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*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource\\.", "title": "DomainName" }, "EndpointConfiguration": { @@ -8398,7 +8547,7 @@ "type": "string" } ], - "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain. The value of this property determines how the `CertificateArn` property is mapped in CloudFormation. \nThe only valid value for HTTP APIs is `REGIONAL`. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain\\. The value of this property determines how the `CertificateArn` property is mapped in AWS CloudFormation\\. \nThe only valid value for HTTP APIs is `REGIONAL`\\. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "EndpointConfiguration" }, "MutualTlsAuthentication": { @@ -8407,7 +8556,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The mutual transport layer security (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/TLS.html) authentication configuration for a custom domain name. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource.", + "markdownDescription": "The mutual transport layer security \\(TLS\\) authentication configuration for a custom domain name\\. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource\\.", "title": "MutualTlsAuthentication" }, "OwnershipVerificationCertificateArn": { @@ -8416,7 +8565,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type.", + "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain\\. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", "title": "OwnershipVerificationCertificateArn" }, "Route53": { @@ -8425,7 +8574,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Route53" } ], - "markdownDescription": "Defines an Amazon Route\u00a053 configuration. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Route53" }, "SecurityPolicy": { @@ -8434,7 +8583,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The TLS version of the security policy for this domain name. \nThe only valid value for HTTP APIs is `TLS_1_2`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type.", + "markdownDescription": "The TLS version of the security policy for this domain name\\. \nThe only valid value for HTTP APIs is `TLS_1_2`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", "title": "SecurityPolicy" } }, @@ -8454,7 +8603,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The settings for access logging in a stage. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The settings for access logging in a stage\\. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "AccessLogSettings" }, "Auth": { @@ -8463,7 +8612,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Auth" } ], - "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API\\. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*\\. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Auth" }, "CorsConfiguration": { @@ -8472,7 +8621,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Manages cross-origin resource sharing (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html) for all your API Gateway HTTP APIs. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object. Note that https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html requires AWS SAM to modify your OpenAPI definition, so https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html works only if the `DefinitionBody` property is specified. \nFor more information, see [Configuring https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence. If this property is set to `true`, then all origins are allowed.\n*Type*: String \\$1 [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Manages cross\\-origin resource sharing \\(CORS\\) for all your API Gateway HTTP APIs\\. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object\\. Note that CORS requires AWS SAM to modify your OpenAPI definition, so CORS works only if the `DefinitionBody` property is specified\\. \nFor more information, see [Configuring CORS for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*\\. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence\\. If this property is set to `true`, then all origins are allowed\\.\n*Type*: String \\| [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "CorsConfiguration" }, "DefaultRouteSettings": { @@ -8481,7 +8630,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The default route settings for this HTTP API. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The default route settings for this HTTP API\\. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "DefaultRouteSettings" }, "Domain": { @@ -8490,7 +8639,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Domain" } ], - "markdownDescription": "Configures a custom domain for this API Gateway HTTP API. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures a custom domain for this API Gateway HTTP API\\. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Domain" }, "FailOnWarnings": { @@ -8499,11 +8648,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether to roll back the HTTP API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "FailOnWarnings" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.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" }, @@ -8513,7 +8662,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The route settings, per route, for this HTTP API. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The route settings, per route, for this HTTP API\\. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "RouteSettings" }, "StageVariables": { @@ -8522,11 +8671,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "A map that defines the stage variables. Variable names can have alphanumeric and underscore characters. The values must match [A-Za-z0-9-.\\$1\\$1:/?\\$1&=,]\\$1. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "A map that defines the stage variables\\. Variable names can have alphanumeric and underscore characters\\. The values must match \\[A\\-Za\\-z0\\-9\\-\\.\\_\\~:/?\\#&=,\\]\\+\\. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageVariables" }, "Tags": { - "markdownDescription": "A map (string to string) that specifies the tags to add to this API Gateway stage. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`. Values can be 1 to 256 Unicode characters in length. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource (if `DomainName` is specified).", + "markdownDescription": "A map \\(string to string\\) that specifies the tags to add to this API Gateway stage\\. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`\\. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`\\. Values can be 1 to 256 Unicode characters in length\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified\\. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag\\. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource \\(if `DomainName` is specified\\)\\.", "title": "Tags", "type": "object" } @@ -8543,7 +8692,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The settings for access logging in a stage. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The settings for access logging in a stage\\. \n*Type*: [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`AccessLogSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-accesslogsettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "AccessLogSettings" }, "Auth": { @@ -8552,7 +8701,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Auth" } ], - "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures authorization for controlling access to your API Gateway HTTP API\\. \nFor more information, see [Controlling access to HTTP APIs with JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) in the *API Gateway Developer Guide*\\. \n*Type*: [HttpApiAuth](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapiauth.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Auth" }, "CorsConfiguration": { @@ -8561,7 +8710,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Manages cross-origin resource sharing (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html) for all your API Gateway HTTP APIs. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object. Note that https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html requires AWS SAM to modify your OpenAPI definition, so https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html works only if the `DefinitionBody` property is specified. \nFor more information, see [Configuring https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/CORS.html for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence. If this property is set to `true`, then all origins are allowed.\n*Type*: String \\$1 [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Manages cross\\-origin resource sharing \\(CORS\\) for all your API Gateway HTTP APIs\\. Specify the domain to allow as a string, or specify an `HttpApiCorsConfiguration` object\\. Note that CORS requires AWS SAM to modify your OpenAPI definition, so CORS works only if the `DefinitionBody` property is specified\\. \nFor more information, see [Configuring CORS for an HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html) in the *API Gateway Developer Guide*\\. \nIf `CorsConfiguration` is set both in an OpenAPI definition and at the property level, then AWS SAM merges both configuration sources with the properties taking precedence\\. If this property is set to `true`, then all origins are allowed\\.\n*Type*: String \\| [HttpApiCorsConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapicorsconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "CorsConfiguration" }, "DefaultRouteSettings": { @@ -8570,11 +8719,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The default route settings for this HTTP API. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The default route settings for this HTTP API\\. These settings apply to all routes unless overridden by the `RouteSettings` property for certain routes\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "DefaultRouteSettings" }, "DefinitionBody": { - "markdownDescription": "The OpenAPI definition that describes your HTTP API. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \n*Type*: JSON \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to CloudFormation. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource.", + "markdownDescription": "The OpenAPI definition that describes your HTTP API\\. If you don't specify a `DefinitionUri` or a `DefinitionBody`, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \n*Type*: JSON \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Body`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body) property of an `AWS::ApiGatewayV2::Api` resource\\. If certain properties are provided, AWS SAM may insert content into or modify the `DefinitionBody` before it is passed to AWS CloudFormation\\. Properties include `Auth` and an `EventSource` of type HttpApi for a corresponding `AWS::Serverless::Function` resource\\.", "title": "DefinitionBody", "type": "object" }, @@ -8587,11 +8736,11 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__DefinitionUri" } ], - "markdownDescription": "The Amazon Simple Storage Service (Amazon S3) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API. The Amazon S3 object that this property references must be a valid OpenAPI definition file. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html). \n*Type*: String \\$1 [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource. The nested Amazon S3 properties are named differently.", + "markdownDescription": "The Amazon Simple Storage Service \\(Amazon S3\\) URI, local file path, or location object of the the OpenAPI definition that defines the HTTP API\\. The Amazon S3 object that this property references must be a valid OpenAPI definition file\\. If you don't specify a `DefinitionUri` or a `DefinitionBody` are specified, AWS SAM generates a `DefinitionBody` for you based on your template configuration\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command for the definition to be transformed properly\\. \nIntrinsic functions are not supported in external OpenApi definition files that you reference with `DefinitionUri`\\. To import an OpenApi definition into the template, use the `DefinitionBody` property with the [Include transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html)\\. \n*Type*: String \\| [HttpApiDefinition](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidefinition.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`BodyS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-bodys3location) property of an `AWS::ApiGatewayV2::Api` resource\\. The nested Amazon S3 properties are named differently\\.", "title": "DefinitionUri" }, "Description": { - "markdownDescription": "The description of the HTTP API resource. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The description of the HTTP API resource\\. \nWhen you specify `Description`, AWS SAM will modify the HTTP API resource's OpenApi definition by setting the `description` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `description` field set in the Open API definition \u2013 This results in a conflict of the `description` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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": "Description", "type": "string" }, @@ -8601,7 +8750,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`. By default, clients can invoke your API with the default endpoint. To require that clients only use a custom domain name to invoke your API, disable the default endpoint. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x-amazon-apigateway-endpoint-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether clients can invoke your HTTP API by using the default `execute-api` endpoint `https://{api_id}.execute-api.{region}.amazonaws.com`\\. By default, clients can invoke your API with the default endpoint\\. To require that clients only use a custom domain name to invoke your API, disable the default endpoint\\. \nTo use this property, you must specify the `DefinitionBody` property instead of the `DefinitionUri` property or define `x-amazon-apigateway-endpoint-configuration` with `disableExecuteApiEndpoint` in your OpenAPI definition\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-disableexecuteapiendpoint)` property of an `AWS::ApiGatewayV2::Api` resource\\. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x\\-amazon\\-apigateway\\-endpoint\\-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-body)` property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "DisableExecuteApiEndpoint" }, "Domain": { @@ -8610,7 +8759,7 @@ "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Domain" } ], - "markdownDescription": "Configures a custom domain for this API Gateway HTTP API. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Configures a custom domain for this API Gateway HTTP API\\. \n*Type*: [HttpApiDomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-httpapidomainconfiguration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Domain" }, "FailOnWarnings": { @@ -8619,7 +8768,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Specifies whether to roll back the HTTP API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource.", + "markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.", "title": "FailOnWarnings" }, "Name": { @@ -8628,11 +8777,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the HTTP API resource. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The name of the HTTP API resource\\. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\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": "Name" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::HttpApi](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.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" }, @@ -8642,7 +8791,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The route settings, per route, for this HTTP API. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The route settings, per route, for this HTTP API\\. For more information, see [Working with routes for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html) in the *API Gateway Developer Guide*\\. \n*Type*: [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RouteSettings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-routesettings) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "RouteSettings" }, "StageName": { @@ -8651,7 +8800,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the API stage. If no name is specified, AWS SAM uses the `$default` stage from API Gateway. \n*Type*: String \n*Required*: No \n*Default*: \\$1default \n*CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "The name of the API stage\\. If no name is specified, AWS SAM uses the `$default` stage from API Gateway\\. \n*Type*: String \n*Required*: No \n*Default*: $default \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagename) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageName" }, "StageVariables": { @@ -8660,11 +8809,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "A map that defines the stage variables. Variable names can have alphanumeric and underscore characters. The values must match [A-Za-z0-9-.\\$1\\$1:/?\\$1&=,]\\$1. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource.", + "markdownDescription": "A map that defines the stage variables\\. Variable names can have alphanumeric and underscore characters\\. The values must match \\[A\\-Za\\-z0\\-9\\-\\.\\_\\~:/?\\#&=,\\]\\+\\. \n*Type*: [Json](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StageVariables`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html#cfn-apigatewayv2-stage-stagevariables) property of an `AWS::ApiGatewayV2::Stage` resource\\.", "title": "StageVariables" }, "Tags": { - "markdownDescription": "A map (string to string) that specifies the tags to add to this API Gateway stage. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`. Values can be 1 to 256 Unicode characters in length. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource (if `DomainName` is specified).", + "markdownDescription": "A map \\(string to string\\) that specifies the tags to add to this API Gateway stage\\. Keys can be 1 to 128 Unicode characters in length and cannot include the prefix `aws:`\\. You can use any of the following characters: the set of Unicode letters, digits, whitespace, `_`, `.`, `/`, `=`, `+`, and `-`\\. Values can be 1 to 256 Unicode characters in length\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\. \n*Additional notes*: The `Tags` property requires AWS SAM to modify your OpenAPI definition, so tags are added only if the `DefinitionBody` property is specified\u2014no tags are added if the `DefinitionUri` property is specified\\. AWS SAM automatically adds an `httpapi:createdBy:SAM` tag\\. Tags are also added to the `AWS::ApiGatewayV2::Stage` resource and the `AWS::ApiGatewayV2::DomainName` resource \\(if `DomainName` is specified\\)\\.", "title": "Tags", "type": "object" } @@ -8737,7 +8886,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Configures a custom distribution of the API custom domain name. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution. \n*CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html).", + "markdownDescription": "Configures a custom distribution of the API custom domain name\\. \n*Type*: String \n*Required*: No \n*Default*: Use the API Gateway distribution\\. \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DNSName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget-1.html#cfn-route53-aliastarget-dnshostname) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: The domain name of a [CloudFront distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html)\\.", "title": "DistributionDomainName" }, "EvaluateTargetHealth": { @@ -8746,7 +8895,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution.", + "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution\\.", "title": "EvaluateTargetHealth" }, "HostedZoneId": { @@ -8755,7 +8904,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ID of the hosted zone that you want to create records in. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", + "markdownDescription": "The ID of the hosted zone that you want to create records in\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", "title": "HostedZoneId" }, "HostedZoneName": { @@ -8764,46 +8913,30 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the hosted zone that you want to create records in. You must include a trailing dot (for example, `www.example.com.`) as part of the `HostedZoneName`. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource.", + "markdownDescription": "The name of the hosted zone that you want to create records in\\. You must include a trailing dot \\(for example, `www.example.com.`\\) as part of the `HostedZoneName`\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", "title": "HostedZoneName" }, "IpV6": { - "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone\\. \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\\.", "title": "IpV6", "type": "boolean" }, "Region": { - "__samPassThrough": { - "markdownDescriptionOverride": "*Latency-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region. Route\u00a053 then returns the value that is associated with the selected resource record set. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set.\n+ You can only create one latency resource record set for each Amazon EC2 Region.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for.\n+ You can't create non-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets.\n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type.", - "schemaPath": [ - "definitions", - "AWS::Route53::RecordSetGroup.RecordSet", - "properties", - "Region" - ] - }, "allOf": [ { "$ref": "#/definitions/PassThroughProp" } ], + "markdownDescription": "*Latency\\-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to\\. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type\\. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region\\. Route\u00a053 then returns the value that is associated with the selected resource record set\\. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set\\.\n+ You can only create one latency resource record set for each Amazon EC2 Region\\.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions\\. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for\\.\n+ You can't create non\\-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", "title": "Region" }, "SetIdentifier": { - "__samPassThrough": { - "markdownDescriptionOverride": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme.example.com that have a type of A. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type.", - "schemaPath": [ - "definitions", - "AWS::Route53::RecordSetGroup.RecordSet", - "properties", - "SetIdentifier" - ] - }, "allOf": [ { "$ref": "#/definitions/PassThroughProp" } ], + "markdownDescription": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme\\.example\\.com that have a type of A\\. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set\\. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", "title": "SetIdentifier" } }, @@ -9531,7 +9664,7 @@ "additionalProperties": false, "properties": { "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.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" } @@ -9546,12 +9679,12 @@ "$ref": "#/definitions/PassThroughProp" }, "Definition": { - "markdownDescription": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples). \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: Map \n*Required*: Conditional \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "The state machine definition is an object, where the format of the object matches the format of your AWS SAM template file, for example, JSON or YAML\\. State machine definitions adhere to the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nFor an example of an inline state machine definition, see [Examples](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/#sam-resource-statemachine--examples.html#sam-resource-statemachine--examples)\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: Map \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Definition", "type": "object" }, "DefinitionSubstitutions": { - "markdownDescription": "A string-to-string map that specifies the mappings for placeholder variables in the state machine definition. This enables you to inject values obtained at runtime (for example, from intrinsic functions) into the state machine definition. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition.", + "markdownDescription": "A string\\-to\\-string map that specifies the mappings for placeholder variables in the state machine definition\\. This enables you to inject values obtained at runtime \\(for example, from intrinsic functions\\) into the state machine definition\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`DefinitionSubstitutions`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitionsubstitutions) property of an `AWS::StepFunctions::StateMachine` resource\\. If any intrinsic functions are specified in an inline state machine definition, AWS SAM adds entries to this property to inject them into the state machine definition\\.", "title": "DefinitionSubstitutions", "type": "object" }, @@ -9564,7 +9697,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The Amazon Simple Storage Service (Amazon S3) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition. To do this, you must use version 0.52.0 or later of the AWS SAM CLI. \nYou must provide either a `Definition` or a `DefinitionUri`. \n*Type*: String \\$1 [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The Amazon Simple Storage Service \\(Amazon S3\\) URI or local file path of the state machine definition written in the [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html)\\. \nIf you provide a local file path, the template must go through the workflow that includes the `sam deploy` or `sam package` command to correctly transform the definition\\. To do this, you must use version 0\\.52\\.0 or later of the AWS SAM CLI\\. \nYou must provide either a `Definition` or a `DefinitionUri`\\. \n*Type*: String \\| [S3Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DefinitionS3Location`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definitions3location) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "DefinitionUri" }, "DeploymentPreference": { @@ -9590,7 +9723,7 @@ } ] }, - "markdownDescription": "Specifies the events that trigger this state machine. Events consist of a type and a set of properties that depend on the type. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Specifies the events that trigger this state machine\\. Events consist of a type and a set of properties that depend on the type\\. \n*Type*: [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-statemachineeventsource.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Events", "type": "object" }, @@ -9600,7 +9733,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Defines which execution history events are logged and where they are logged. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "Defines which execution history events are logged and where they are logged\\. \n*Type*: [LoggingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`LoggingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-loggingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Logging" }, "Name": { @@ -9609,7 +9742,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The name of the state machine. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The name of the state machine\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinename) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Name" }, "PermissionsBoundary": { @@ -9618,7 +9751,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of a permissions boundary to use for this state machine's execution role. This property only works if the role is generated for you. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource.", + "markdownDescription": "The ARN of a permissions boundary to use for this state machine's execution role\\. This property only works if the role is generated for you\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`PermissionsBoundary`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary) property of an `AWS::IAM::Role` resource\\.", "title": "PermissionsBoundary" }, "Policies": { @@ -9643,11 +9776,11 @@ "type": "array" } ], - "markdownDescription": "Permission policies for this state machine. Policies will be appended to the state machine's default AWS Identity and Access Management (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html) 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/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) or [customer managed policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html policy](https://docs.aws.amazon.com/https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/IAM.html/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 \\$1 List \\$1 Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Permission policies for this state machine\\. Policies will be appended to the state machine'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 unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", "title": "Policies" }, "PropagateTags": { - "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.html) generated resources. Specify `True` to propagate tags in your generated resources. \n*Type*: Boolean \n*Required*: No \n*Default*: `False` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "markdownDescription": "Indicate whether or not to pass tags from the `Tags` property to your [AWS::Serverless::StateMachine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-statemachine.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" }, @@ -9657,7 +9790,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The ARN of an IAM role to use as this state machine's execution role. \n*Type*: String \n*Required*: Conditional \n*CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The ARN of an IAM role to use as this state machine's execution role\\. \n*Type*: String \n*Required*: Conditional \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ RoleArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-rolearn)` property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Role" }, "RolePath": { @@ -9666,11 +9799,11 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The path to the state machine'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*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.", + "markdownDescription": "The path to the state machine'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\\.", "title": "RolePath" }, "Tags": { - "markdownDescription": "A string-to-string map that specifies the tags added to the state machine and the corresponding execution role. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource. \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it.", + "markdownDescription": "A string\\-to\\-string map that specifies the tags added to the state machine and the corresponding execution role\\. For information about valid keys and values for tags, see the [Tags](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html) resource\\. \n*Type*: Map \n*Required*: No \n*AWS CloudFormation compatibility*: This property is similar to the [`Tags`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags) property of an `AWS::StepFunctions::StateMachine` resource\\. AWS SAM automatically adds a `stateMachine:createdBy:SAM` tag to this resource, and to the default role that is generated for it\\.", "title": "Tags", "type": "object" }, @@ -9680,7 +9813,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "Selects whether or not AWS X-Ray is enabled for the state machine. For more information about using X-Ray with Step Functions, see [AWS X-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "Selects whether or not AWS X\\-Ray is enabled for the state machine\\. For more information about using X\\-Ray with Step Functions, see [AWS X\\-Ray and Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) in the *AWS Step Functions Developer Guide*\\. \n*Type*: [TracingConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`TracingConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tracingconfiguration) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Tracing" }, "Type": { @@ -9689,7 +9822,7 @@ "$ref": "#/definitions/PassThroughProp" } ], - "markdownDescription": "The type of the state machine. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource.", + "markdownDescription": "The type of the state machine\\. \n*Valid values*: `STANDARD` or `EXPRESS` \n*Type*: String \n*Required*: No \n*Default*: `STANDARD` \n*AWS CloudFormation compatibility*: This property is passed directly to the [`StateMachineType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype) property of an `AWS::StepFunctions::StateMachine` resource\\.", "title": "Type" }, "UseAliasAsEventTarget": { @@ -10131,6 +10264,434 @@ }, "title": "ScheduleV2EventProperties", "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain": { + "additionalProperties": false, + "properties": { + "BasePath": { + "items": { + "type": "string" + }, + "markdownDescription": "A list of the basepaths to configure with the Amazon API Gateway domain name\\. \n*Type*: List \n*Required*: No \n*Default*: / \n*AWS CloudFormation compatibility*: This property is similar to the [`ApiMappingKey`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-apimapping.html#cfn-apigatewayv2-apimapping-apimappingkey) property of an `AWS::ApiGatewayV2::ApiMapping` resource\\. AWS SAM creates multiple `AWS::ApiGatewayV2::ApiMapping` resources, one per value specified in this property\\.", + "title": "BasePath", + "type": "array" + }, + "CertificateArn": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The Amazon Resource Name \\(ARN\\) of an AWS managed certificate for this domain name's endpoint\\. AWS Certificate Manager is the only supported source\\. \n*Type*: String \n*Required*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-certificatearn) property of an `AWS::ApiGateway2::DomainName DomainNameConfiguration` resource\\.", + "title": "CertificateArn" + }, + "DomainName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The custom domain name for your API Gateway API\\. Uppercase letters are not supported\\. \nAWS SAM generates an `AWS::ApiGatewayV2::DomainName` resource when this property is set\\. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-httpapi.html#sam-specification-generated-resources-httpapi-domain-name)\\. For 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*: Yes \n*AWS CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-domainname) property of an `AWS::ApiGateway2::DomainName` resource\\.", + "title": "DomainName" + }, + "EndpointConfiguration": { + "anyOf": [ + { + "type": "object" + }, + { + "enum": [ + "REGIONAL" + ], + "type": "string" + } + ], + "markdownDescription": "Defines the type of API Gateway endpoint to map to the custom domain\\. The value of this property determines how the `CertificateArn` property is mapped in AWS CloudFormation\\. \nThe only valid value for HTTP APIs is `REGIONAL`\\. \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "EndpointConfiguration" + }, + "MutualTlsAuthentication": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The mutual transport layer security \\(TLS\\) authentication configuration for a custom domain name\\. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-domainname.html#cfn-apigatewayv2-domainname-mutualtlsauthentication) property of an `AWS::ApiGatewayV2::DomainName` resource\\.", + "title": "MutualTlsAuthentication" + }, + "OwnershipVerificationCertificateArn": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain\\. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-ownershipverificationcertificatearn) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", + "title": "OwnershipVerificationCertificateArn" + }, + "Route53": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Route53" + } + ], + "markdownDescription": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.", + "title": "Route53" + }, + "SecurityPolicy": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The TLS version of the security policy for this domain name\\. \nThe only valid value for HTTP APIs is `TLS_1_2`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`SecurityPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-domainname-domainnameconfiguration.html#cfn-apigatewayv2-domainname-domainnameconfiguration-securitypolicy) property of the `AWS::ApiGatewayV2::DomainName` `DomainNameConfiguration` data type\\.", + "title": "SecurityPolicy" + } + }, + "required": [ + "CertificateArn", + "DomainName" + ], + "title": "Domain", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Globals": { + "additionalProperties": false, + "properties": { + "AccessLogSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AccessLogSettings" + }, + "ApiKeySelectionExpression": { + "markdownDescription": "TODO", + "title": "ApiKeySelectionExpression", + "type": "string" + }, + "DefaultRouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DefaultRouteSettings" + }, + "DisableExecuteApiEndpoint": { + "markdownDescription": "TODO", + "title": "DisableExecuteApiEndpoint", + "type": "boolean" + }, + "DisableSchemaValidation": { + "markdownDescription": "TODO", + "title": "DisableSchemaValidation", + "type": "boolean" + }, + "Domain": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain" + } + ], + "markdownDescription": "TODO", + "title": "Domain" + }, + "IpAddressType": { + "markdownDescription": "TODO", + "title": "IpAddressType", + "type": "string" + }, + "PropagateTags": { + "markdownDescription": "TODO", + "title": "PropagateTags", + "type": "boolean" + }, + "RouteSelectionExpression": { + "markdownDescription": "TODO", + "title": "RouteSelectionExpression", + "type": "string" + }, + "RouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSettings" + }, + "StageVariables": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageVariables" + }, + "Tags": { + "markdownDescription": "TODO", + "title": "Tags", + "type": "object" + } + }, + "title": "Globals", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Properties": { + "additionalProperties": false, + "properties": { + "AccessLogSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "AccessLogSettings" + }, + "ApiKeySelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "ApiKeySelectionExpression" + }, + "Auth": { + "allOf": [ + { + "$ref": "#/definitions/AuthConfig" + } + ], + "markdownDescription": "TODO", + "title": "Auth" + }, + "DefaultRouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DefaultRouteSettings" + }, + "Description": { + "markdownDescription": "TODO", + "title": "Description", + "type": "string" + }, + "DisableExecuteApiEndpoint": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "DisableExecuteApiEndpoint" + }, + "DisableSchemaValidation": { + "markdownDescription": "TODO", + "title": "DisableSchemaValidation", + "type": "boolean" + }, + "Domain": { + "allOf": [ + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Domain" + } + ], + "markdownDescription": "TODO", + "title": "Domain" + }, + "IpAddressType": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "IpAddressType" + }, + "Name": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "Name" + }, + "PropagateTags": { + "markdownDescription": "TODO", + "title": "PropagateTags", + "type": "boolean" + }, + "RouteSelectionExpression": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSelectionExpression" + }, + "RouteSettings": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "RouteSettings" + }, + "Routes": { + "additionalProperties": { + "$ref": "#/definitions/WebSocketApiRoute" + }, + "markdownDescription": "TODO", + "title": "Routes", + "type": "object" + }, + "StageName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageName" + }, + "StageVariables": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "TODO", + "title": "StageVariables" + }, + "Tags": { + "markdownDescription": "TODO", + "title": "Tags", + "type": "object" + } + }, + "required": [ + "Routes", + "RouteSelectionExpression" + ], + "title": "Properties", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__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_websocketapi__Properties" + }, + "Type": { + "enum": [ + "AWS::Serverless::WebSocketApi" + ], + "title": "Type", + "type": "string" + }, + "UpdateReplacePolicy": { + "$ref": "#/definitions/PassThroughProp" + } + }, + "required": [ + "Type" + ], + "title": "Resource", + "type": "object" + }, + "samtranslator__internal__schema_source__aws_serverless_websocketapi__Route53": { + "additionalProperties": false, + "properties": { + "EvaluateTargetHealth": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "When EvaluateTargetHealth is true, an alias record inherits the health of the referenced AWS resource, such as an Elastic Load Balancing load balancer or another record in the hosted zone\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EvaluateTargetHealth`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-evaluatetargethealth) property of an `AWS::Route53::RecordSetGroup AliasTarget` resource\\. \n*Additional notes*: You can't set EvaluateTargetHealth to true when the alias target is a CloudFront distribution\\.", + "title": "EvaluateTargetHealth" + }, + "HostedZoneId": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The ID of the hosted zone that you want to create records in\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzoneid) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "title": "HostedZoneId" + }, + "HostedZoneName": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "The name of the hosted zone that you want to create records in\\. You must include a trailing dot \\(for example, `www.example.com.`\\) as part of the `HostedZoneName`\\. \nSpecify either `HostedZoneName` or `HostedZoneId`, but not both\\. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using `HostedZoneId`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`HostedZoneName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-hostedzonename) property of an `AWS::Route53::RecordSetGroup RecordSet` resource\\.", + "title": "HostedZoneName" + }, + "IpV6": { + "markdownDescription": "When this property is set, AWS SAM creates a `AWS::Route53::RecordSet` resource and sets [Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-type) to `AAAA` for the provided HostedZone\\. \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\\.", + "title": "IpV6", + "type": "boolean" + }, + "Region": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Latency\\-based resource record sets only:* The Amazon EC2 Region where you created the resource that this resource record set refers to\\. The resource typically is an AWS resource, such as an EC2 instance or an ELB load balancer, and is referred to by an IP address or a DNS domain name, depending on the record type\\. \nWhen Amazon Route\u00a053 receives a DNS query for a domain name and type for which you have created latency resource record sets, Route\u00a053 selects the latency resource record set that has the lowest latency between the end user and the associated Amazon EC2 Region\\. Route\u00a053 then returns the value that is associated with the selected resource record set\\. \nNote the following: \n+ You can only specify one `ResourceRecord` per latency resource record set\\.\n+ You can only create one latency resource record set for each Amazon EC2 Region\\.\n+ You aren't required to create latency resource record sets for all Amazon EC2 Regions\\. Route\u00a053 will choose the region with the best latency from among the regions that you create latency resource record sets for\\.\n+ You can't create non\\-latency resource record sets that have the same values for the `Name` and `Type` elements as latency resource record sets\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ Region](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-region)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "Region" + }, + "SetIdentifier": { + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "markdownDescription": "*Resource record sets that have a routing policy other than simple:* An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme\\.example\\.com that have a type of A\\. In a group of resource record sets that have the same name and type, the value of `SetIdentifier` must be unique for each resource record set\\. \nFor information about routing policies, see [Choosing a routing policy](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) in the *Amazon Route\u00a053 Developer Guide*\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the `[ SetIdentifier](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-1.html#cfn-route53-recordset-setidentifier)` property of an `AWS::Route53::RecordSetGroup` `RecordSet` data type\\.", + "title": "SetIdentifier" + } + }, + "title": "Route53", + "type": "object" } }, "properties": { @@ -10161,6 +10722,9 @@ { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_httpapi__Resource" }, + { + "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_websocketapi__Resource" + }, { "$ref": "#/definitions/samtranslator__internal__schema_source__aws_serverless_application__Resource" }, diff --git a/tests/model/api/test_apiv2_generator.py b/tests/model/api/test_apiv2_generator.py new file mode 100644 index 0000000000..b738c177cb --- /dev/null +++ b/tests/model/api/test_apiv2_generator.py @@ -0,0 +1,350 @@ +from unittest import TestCase + +import pytest +from samtranslator.model import InvalidResourceException +from samtranslator.model.api.http_api_generator import HttpApiGenerator +from samtranslator.model.api.websocket_api_generator import WebSocketApiGenerator + + +class TestCustomDomains(TestCase): + http_kwargs = { + "logical_id": "HttpApiId", + "stage_variables": None, + "depends_on": None, + "definition_body": None, + "definition_uri": "s3://bucket/key", + "name": None, + "stage_name": None, + "tags": None, + "auth": None, + "access_log_settings": None, + "resource_attributes": None, + "passthrough_resource_attributes": None, + "domain": None, + } + + websocket_kwargs = { + "logical_id": "WebSocketApiId", + "stage_variables": None, + "depends_on": None, + "name": "WebSocketApi", + "stage_name": None, + "tags": None, + "auth_config": None, + "access_log_settings": None, + "resource_attributes": None, + "routes": {"$default": {"FunctionName": {"Ref": "DefaultFunction"}}}, + "route_selection_expression": "$request.body.action", + "passthrough_resource_attributes": None, + "domain": None, + } + + def setUp(self) -> None: + self.route53_record_set_groups = {} + + def test_no_domain(self): + self.http_kwargs["domain"] = None + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNone(domain) + self.assertIsNone(basepath) + self.assertIsNone(route) + self.websocket_kwargs["domain"] = None + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNone(domain) + self.assertIsNone(basepath) + self.assertIsNone(route) + + def test_no_domain_name(self): + self.http_kwargs["domain"] = {"CertificateArn": "someurl"} + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.http_kwargs)._construct_api_domain(http_api, self.route53_record_set_groups) + self.assertEqual( + e.value.message, + "Resource with id [HttpApiId] is invalid. " + + "Custom Domains only works if both DomainName and CertificateArn are provided.", + ) + self.websocket_kwargs["domain"] = {"CertificateArn": "someurl"} + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "Custom Domains only works if both DomainName and CertificateArn are provided.", + ) + + def test_no_cert_arn(self): + self.http_kwargs["domain"] = {"DomainName": "example.com"} + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.http_kwargs)._construct_api_domain(http_api, self.route53_record_set_groups) + self.assertEqual( + e.value.message, + "Resource with id [HttpApiId] is invalid. " + + "Custom Domains only works if both DomainName and CertificateArn are provided.", + ) + self.websocket_kwargs["domain"] = {"DomainName": "example.com"} + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "Custom Domains only works if both DomainName and CertificateArn are provided.", + ) + + def test_basic_domain_default_endpoint(self): + self.http_kwargs["domain"] = {"DomainName": "example.com", "CertificateArn": "some-url"} + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + self.websocket_kwargs["domain"] = {"DomainName": "example.com", "CertificateArn": "some-url"} + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() # throws an erri + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + + def test_basic_domain_regional_endpoint(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "REGIONAL", + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "REGIONAL", + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + + def test_basic_domain_edge_endpoint(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "EDGE", + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.http_kwargs)._construct_api_domain(http_api, self.route53_record_set_groups) + self.assertEqual( + e.value.message, + "Resource with id [HttpApiId] is invalid. EndpointConfiguration for Custom Domains must be one of ['REGIONAL'].", + ) + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "EDGE", + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. EndpointConfiguration for Custom Domains must be one of ['REGIONAL'].", + ) + + def test_bad_endpoint(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "INVALID", + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.http_kwargs)._construct_api_domain(http_api, self.route53_record_set_groups) + self.assertEqual( + e.value.message, + "Resource with id [HttpApiId] is invalid. " + + "EndpointConfiguration for Custom Domains must be one of ['REGIONAL'].", + ) + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "EndpointConfiguration": "INVALID", + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "EndpointConfiguration for Custom Domains must be one of ['REGIONAL'].", + ) + + def test_basic_route53(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "Route53": {"HostedZoneId": "xyz"}, + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNotNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "Route53": {"HostedZoneId": "xyz"}, + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 1) + self.assertIsNotNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + + def test_basepaths(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["one", "two", "three"], + "Route53": {"HostedZoneId": "xyz"}, + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 3) + self.assertIsNotNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["one", "two", "three"], + "Route53": {"HostedZoneId": "xyz"}, + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 3) + self.assertIsNotNone(route, None) + self.assertEqual(domain.DomainNameConfigurations[0].get("EndpointType"), "REGIONAL") + + def test_invalid_basepaths(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["inv*alid"], + "Route53": {"HostedZoneId": "xyz"}, + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.http_kwargs)._construct_api_domain(http_api, self.route53_record_set_groups) + self.assertEqual( + e.value.message, "Resource with id [HttpApiId] is invalid. " + "Invalid Basepath name provided." + ) + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["inv*alid"], + "Route53": {"HostedZoneId": "xyz"}, + } + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertEqual( + e.value.message, "Resource with id [WebSocketApiId] is invalid. " + "Invalid Basepath name provided." + ) + + def test_basepaths_complex(self): + self.http_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["one-1", "two_2", "three", "/", "/api", "api/v1", "api/v1/", "/api/v1/"], + "Route53": {"HostedZoneId": "xyz", "HostedZoneName": "abc", "IpV6": True}, + } + http_api = HttpApiGenerator(**self.http_kwargs)._construct_http_api() + domain, basepath, route = HttpApiGenerator(**self.http_kwargs)._construct_api_domain( + http_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 8) + self.assertIsNotNone(route, None) + self.assertEqual(route.HostedZoneName, None) + self.assertEqual(route.HostedZoneId, "xyz") + self.assertEqual(len(route.RecordSets), 2) + self.assertEqual( + list(map(lambda base: base.ApiMappingKey, basepath)), + ["one-1", "two_2", "three", "", "api", "api/v1", "api/v1", "api/v1"], + ) + self.websocket_kwargs["domain"] = { + "DomainName": "example.com", + "CertificateArn": "some-url", + "BasePath": ["one-1", "two_2", "three", "/", "/api", "api/v1", "api/v1/", "/api/v1/"], + "Route53": {"HostedZoneId": "xyz", "HostedZoneName": "abc", "IpV6": True}, + } + self.route53_record_set_groups = {} # This needs to be reset because it is edited within the function + websocket_api = WebSocketApiGenerator(**self.websocket_kwargs)._construct_websocket_api() + domain, basepath, route = WebSocketApiGenerator(**self.websocket_kwargs)._construct_api_domain( + websocket_api, self.route53_record_set_groups + ) + self.assertIsNotNone(domain, None) + self.assertIsNotNone(basepath, None) + self.assertEqual(len(basepath), 8) + self.assertIsNotNone(route, None) + self.assertEqual(route.HostedZoneName, None) + self.assertEqual(route.HostedZoneId, "xyz") + self.assertEqual(len(route.RecordSets), 2) + self.assertEqual( + list(map(lambda base: base.ApiMappingKey, basepath)), + ["one-1", "two_2", "three", "", "api", "api/v1", "api/v1", "api/v1"], + ) diff --git a/tests/model/api/test_websocket_api_generator.py b/tests/model/api/test_websocket_api_generator.py new file mode 100644 index 0000000000..ec2a5434c8 --- /dev/null +++ b/tests/model/api/test_websocket_api_generator.py @@ -0,0 +1,216 @@ +from unittest import TestCase + +import pytest +from samtranslator.model import InvalidResourceException +from samtranslator.model.api.websocket_api_generator import WebSocketApiGenerator + + +class TestWebSocketApiGenerator(TestCase): + kwargs = { + "logical_id": "WebSocketApiId", + "stage_variables": None, + "depends_on": None, + "name": "WebSocketApi", + "stage_name": None, + "tags": None, + "auth_config": None, + "ip_address_type": None, + "access_log_settings": None, + "resource_attributes": None, + "routes": {"$connect": {"FunctionArn": {"Fn::GetAtt": ["ConnectFunction", "Arn"]}}}, + "route_selection_expression": "$request.body.action", + "passthrough_resource_attributes": None, + "domain": None, + } + + def test_auto_generated_name(self): + kwargs = self.kwargs.copy() + kwargs["name"] = None + api = WebSocketApiGenerator(**kwargs)._construct_websocket_api() + self.assertEqual(api.Name, "WebSocketApiId") + + def test_auth_type_no_id(self): + kwargs = self.kwargs.copy() + # A copy is created because using self.kwargs directly required resetting the values at the end. + # In this case, a failed test could exit before resetting the value and cause problems for other tests. + kwargs["auth_config"] = {"AuthType": "AWS_IAM"} + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + r, _, _, _ = WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual(r.AuthorizationType, "AWS_IAM") + + def test_perms(self): + kwargs = self.kwargs.copy() + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + _, _, perm, _ = WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual( + perm.SourceArn["Fn::Sub"], + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApiId.ApiId}/default/$connect", + ) + + def test_none_auth_no_id(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthType": "NONE"} + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + route, _, _, auth = WebSocketApiGenerator(**kwargs)._construct_route_infr( + "$connect", kwargs["routes"]["$connect"] + ) + self.assertEqual(route.AuthorizationType, "NONE") + self.assertIsNone(route.AuthorizerId) + self.assertIsNone(auth) + + def test_none_auth_has_id(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = { + "AuthArn": {"Fn::GetAtt": ["AuthFunc", "Arn"]}, + } + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "AuthType must be specified for additional auth configurations.", + ) + + def test_auth_id_no_type(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthArn": {"Fn::GetAtt": ["saucefunction", "Arn"]}} + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "AuthType must be specified for additional auth configurations.", + ) + + def test_auth_no_connect(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthType": "CUSTOM", "AuthArn": {"Fn::GetAtt": ["AuthFunc", "Arn"]}} + kwargs["routes"] = {"$default": {"FunctionArn": {"Fn::GetAtt": ["DefaultFunction", "Arn"]}}} + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "Authorization is only available if there is a $connect route.", + ) + + def test_none_auth_no_connect(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthType": "NONE"} + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + route, _, _, auth = WebSocketApiGenerator(**kwargs)._construct_route_infr( + "$connect", kwargs["routes"]["$connect"] + ) + self.assertEqual(route.AuthorizationType, "NONE") + self.assertIsNone(route.AuthorizerId) + self.assertIsNone(auth) + + def test_invalid_auth_type(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthType": "nonsense", "AuthArn": {"Fn::GetAtt": ["AuthFunction", "Arn"]}} + + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + "AuthType is not one of AWS_IAM, CUSTOM or NONE.", + ) + + def test_auth_set(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = {"AuthType": "CUSTOM", "AuthArn": {"Fn::GetAtt": ["AuthFunction", "Arn"]}} + kwargs["routes"] = { + "$connect": {"FunctionArn": {"Fn::GetAtt": ["ConnectFunction", "Arn"]}}, + "$disconnect": {"FunctionArn": {"Fn::GetAtt": ["AuthFunction", "Arn"]}}, + } + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + croute, _, _, cauth = WebSocketApiGenerator(**kwargs)._construct_route_infr( + "$connect", kwargs["routes"]["$connect"] + ) + self.assertEqual(croute.AuthorizationType, "CUSTOM") + self.assertEqual(croute.AuthorizerId, {"Ref": cauth.logical_id}) + self.assertIsNotNone(cauth) + droute, _, _, dauth = WebSocketApiGenerator(**kwargs)._construct_route_infr( + "$disconnect", kwargs["routes"]["$disconnect"] + ) + self.assertIsNone(droute.AuthorizationType) + self.assertIsNone(droute.AuthorizerId) + self.assertIsNone(dauth) + + def test_custom_auth_params(self): + kwargs = self.kwargs.copy() + kwargs["auth_config"] = { + "AuthArn": {"Fn::GetAtt": ["AuthFunc", "Arn"]}, + "AuthType": "CUSTOM", + "InvokeRole": {"Fn::GetAtt": ["AuthInvokeRole", "Arn"]}, + "IdentitySource": ["id_source"], + "Name": "Auth", + } + + def test_route_no_function_name(self): + kwargs = self.kwargs.copy() + kwargs["routes"] = {"$connect": {}} + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_route_infr("$connect", kwargs["routes"]["$connect"]) + self.assertEqual( + e.value.message, "Resource with id [WebSocketApiId] is invalid. Route must have associated function." + ) + + def test_invalid_route_name(self): + kwargs = self.kwargs.copy() + kwargs["routes"] = {"$sauce": {"FunctionArn": {"Fn::GetAtt": ["SauceFunction", "Arn"]}}} + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_route_infr("$sauce", kwargs["routes"]["$sauce"]) + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + + "Route key '$sauce' must be alphanumeric. Only $connect, $disconnect, and $default special routes are supported.", + ) + + def test_no_stage_name(self): + kwargs = self.kwargs.copy() + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + stage = WebSocketApiGenerator(**kwargs)._construct_stage() + self.assertEqual(stage.StageName, "default") + + def test_set_stage_name(self): + kwargs = self.kwargs.copy() + kwargs["stage_name"] = "prod" + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + stage = WebSocketApiGenerator(**kwargs)._construct_stage() + self.assertEqual(stage.StageName, "prod") + + def test_invalid_stage_name(self): + kwargs = self.kwargs.copy() + kwargs["stage_name"] = "$default" + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_stage() + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + "Stages cannot be named $default for WebSocket APIs.", + ) + + def test_ipv4(self): + kwargs = self.kwargs.copy() + kwargs["ip_address_type"] = "ipv4" + websocket_api = WebSocketApiGenerator(**kwargs)._construct_websocket_api() + self.assertEqual(websocket_api.IpAddressType, "ipv4") + + def test_dualstack(self): + kwargs = self.kwargs.copy() + kwargs["ip_address_type"] = "dualstack" + websocket_api = WebSocketApiGenerator(**kwargs)._construct_websocket_api() + self.assertEqual(websocket_api.IpAddressType, "dualstack") + + def test_invalid_ip(self): + kwargs = self.kwargs.copy() + kwargs["ip_address_type"] = "nonsense" + with pytest.raises(InvalidResourceException) as e: + WebSocketApiGenerator(**kwargs)._construct_websocket_api() + self.assertEqual( + e.value.message, + "Resource with id [WebSocketApiId] is invalid. " + "IpAddressType must be 'ipv4' or 'dualstack'.", + ) diff --git a/tests/translator/input/error_websocket_api_auth_no_connect.yaml b/tests/translator/input/error_websocket_api_auth_no_connect.yaml new file mode 100644 index 0000000000..8f5aea12a8 --- /dev/null +++ b/tests/translator/input/error_websocket_api_auth_no_connect.yaml @@ -0,0 +1,24 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + AuthArn: !GetAtt AuthFunc.Arn + Name: WSApi + Routes: + $default: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_authid_no_authtype.yaml b/tests/translator/input/error_websocket_api_authid_no_authtype.yaml new file mode 100644 index 0000000000..c3bfafc8d6 --- /dev/null +++ b/tests/translator/input/error_websocket_api_authid_no_authtype.yaml @@ -0,0 +1,23 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthArn: !GetAtt AuthFunc.Arn + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_authid_none_auth.yaml b/tests/translator/input/error_websocket_api_authid_none_auth.yaml new file mode 100644 index 0000000000..b3c1c392a3 --- /dev/null +++ b/tests/translator/input/error_websocket_api_authid_none_auth.yaml @@ -0,0 +1,24 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: NONE + AuthArn: !GetAtt AuthFunc.Arn + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_authtype_no_authid.yaml b/tests/translator/input/error_websocket_api_authtype_no_authid.yaml new file mode 100644 index 0000000000..cc1a34e6af --- /dev/null +++ b/tests/translator/input/error_websocket_api_authtype_no_authid.yaml @@ -0,0 +1,23 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_config_no_auth.yaml b/tests/translator/input/error_websocket_api_config_no_auth.yaml new file mode 100644 index 0000000000..2a24257393 --- /dev/null +++ b/tests/translator/input/error_websocket_api_config_no_auth.yaml @@ -0,0 +1,23 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + PayloadFormatVersion: '1.0' + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_empty_routes.yaml b/tests/translator/input/error_websocket_api_empty_routes.yaml new file mode 100644 index 0000000000..0d9453bd97 --- /dev/null +++ b/tests/translator/input/error_websocket_api_empty_routes.yaml @@ -0,0 +1,13 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Routes: {} + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_iam_auth_config.yaml b/tests/translator/input/error_websocket_api_iam_auth_config.yaml new file mode 100644 index 0000000000..99e699187d --- /dev/null +++ b/tests/translator/input/error_websocket_api_iam_auth_config.yaml @@ -0,0 +1,24 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: AWS_IAM + PayloadFormatVersion: '1.0' + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_invalid_authtype.yaml b/tests/translator/input/error_websocket_api_invalid_authtype.yaml new file mode 100644 index 0000000000..c9c4fda34d --- /dev/null +++ b/tests/translator/input/error_websocket_api_invalid_authtype.yaml @@ -0,0 +1,24 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: Nonsense + AuthArn: !GetAtt AuthFunc + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_invalid_basepath_type.yaml b/tests/translator/input/error_websocket_api_invalid_basepath_type.yaml new file mode 100644 index 0000000000..932be3c320 --- /dev/null +++ b/tests/translator/input/error_websocket_api_invalid_basepath_type.yaml @@ -0,0 +1,21 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Domain: + DomainName: domain-name + CertificateArn: + Ref: CertificateArn + BasePath: + - Fn::Sub: /${BasePathId} + Routes: + $default: + FunctionArn: !GetAtt default.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_invalid_ip_address_type.yaml b/tests/translator/input/error_websocket_api_invalid_ip_address_type.yaml new file mode 100644 index 0000000000..f2cdc7438e --- /dev/null +++ b/tests/translator/input/error_websocket_api_invalid_ip_address_type.yaml @@ -0,0 +1,16 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + IpAddressType: nonsense + Name: WSApi + Routes: + $default: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_invalid_route_name.yaml b/tests/translator/input/error_websocket_api_invalid_route_name.yaml new file mode 100644 index 0000000000..ffc2b8454d --- /dev/null +++ b/tests/translator/input/error_websocket_api_invalid_route_name.yaml @@ -0,0 +1,15 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Routes: + $nonsense: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_invalid_stage_name.yaml b/tests/translator/input/error_websocket_api_invalid_stage_name.yaml new file mode 100644 index 0000000000..ad1a1c0799 --- /dev/null +++ b/tests/translator/input/error_websocket_api_invalid_stage_name.yaml @@ -0,0 +1,16 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + StageName: $default + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_list_access_log_settings.yaml b/tests/translator/input/error_websocket_api_list_access_log_settings.yaml new file mode 100644 index 0000000000..0ea6a611ed --- /dev/null +++ b/tests/translator/input/error_websocket_api_list_access_log_settings.yaml @@ -0,0 +1,17 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + AccessLogSettings: + - DestinationArn: arn1 + Format: $context.requestId + Name: WSApi + Routes: + $default: !GetAtt Func.Arn.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_list_default_route_settings.yaml b/tests/translator/input/error_websocket_api_list_default_route_settings.yaml new file mode 100644 index 0000000000..6a7687283d --- /dev/null +++ b/tests/translator/input/error_websocket_api_list_default_route_settings.yaml @@ -0,0 +1,18 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + DefaultRouteSettings: + - RouteKey: !Sub 'ANY /${ChatApiName}' + ThrottlingBurstLimit: 100 + ThrottlingRateLimit: 100 + Name: WSApi + Routes: + $default: !Ref Func + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_list_route_settings.yaml b/tests/translator/input/error_websocket_api_list_route_settings.yaml new file mode 100644 index 0000000000..7e1f490586 --- /dev/null +++ b/tests/translator/input/error_websocket_api_list_route_settings.yaml @@ -0,0 +1,18 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + RouteSettings: + - RouteKey: !Sub 'ANY /${ChatApiName}' + ThrottlingBurstLimit: 100 + ThrottlingRateLimit: 100 + Routes: + $default: !Ref Func + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_no_route_selection_expression.yaml b/tests/translator/input/error_websocket_api_no_route_selection_expression.yaml new file mode 100644 index 0000000000..d8d1478072 --- /dev/null +++ b/tests/translator/input/error_websocket_api_no_route_selection_expression.yaml @@ -0,0 +1,14 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Routes: + $default: + FunctionArn: !GetAtt Func.Arn diff --git a/tests/translator/input/error_websocket_api_no_routes.yaml b/tests/translator/input/error_websocket_api_no_routes.yaml new file mode 100644 index 0000000000..144e69719c --- /dev/null +++ b/tests/translator/input/error_websocket_api_no_routes.yaml @@ -0,0 +1,12 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_non_connect_request_parameters.yaml b/tests/translator/input/error_websocket_api_non_connect_request_parameters.yaml new file mode 100644 index 0000000000..8a82537b1f --- /dev/null +++ b/tests/translator/input/error_websocket_api_non_connect_request_parameters.yaml @@ -0,0 +1,18 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Routes: + $default: + FunctionArn: !GetAtt Func.Arn + RequestParameters: + route.request.querystring.p1: + Required: true + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_none_auth_config.yaml b/tests/translator/input/error_websocket_api_none_auth_config.yaml new file mode 100644 index 0000000000..a54809bf8d --- /dev/null +++ b/tests/translator/input/error_websocket_api_none_auth_config.yaml @@ -0,0 +1,24 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + AuthFunc: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://buckety/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: None + PayloadFormatVersion: '1.0' + Name: WSApi + Routes: + $connect: + FunctionArn: !GetAtt Func.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/error_websocket_api_route_no_function.yaml b/tests/translator/input/error_websocket_api_route_no_function.yaml new file mode 100644 index 0000000000..7e32a68f2f --- /dev/null +++ b/tests/translator/input/error_websocket_api_route_no_function.yaml @@ -0,0 +1,15 @@ +Resources: + Func: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.14 + Handler: index.handler + CodeUri: s3://bucket/key + WSApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WSApi + Routes: + $connect: + IntegrationTimeout: 15000 + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_api_config.yaml b/tests/translator/input/websocket_api_api_config.yaml new file mode 100644 index 0000000000..cfd344f907 --- /dev/null +++ b/tests/translator/input/websocket_api_api_config.yaml @@ -0,0 +1,19 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + ApiKeySelectionExpression: Api.RouteSelectionExpression + DisableExecuteApiEndpoint: true + DisableSchemaValidation: true + IpAddressType: dualstack + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_api_globals.yaml b/tests/translator/input/websocket_api_api_globals.yaml new file mode 100644 index 0000000000..b61fcf6c03 --- /dev/null +++ b/tests/translator/input/websocket_api_api_globals.yaml @@ -0,0 +1,46 @@ +Globals: + WebSocketApi: + ApiKeySelectionExpression: Api.RouteSelectionExpression + DisableExecuteApiEndpoint: true + DisableSchemaValidation: true + PropagateTags: true + Tags: + tag1: val1 + tag2: val2 + +Resources: + Connect1: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Connect2: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Api1: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: Api1 + Routes: + $connect: + FunctionArn: !GetAtt Connect1.Arn + RouteSelectionExpression: $request.body.action + Api2: + Type: AWS::Serverless::WebSocketApi + Properties: + ApiKeySelectionExpression: Integration.TemplateSelectionExpression + DisableExecuteApiEndpoint: false + DisableSchemaValidation: false + PropagateTags: false + Name: Api2 + Routes: + $connect: + FunctionArn: !GetAtt Connect2.Arn + RouteSelectionExpression: $request.body.message + Tags: + tag2: val4 + tag3: val3 diff --git a/tests/translator/input/websocket_api_auto_name.yaml b/tests/translator/input/websocket_api_auto_name.yaml new file mode 100644 index 0000000000..8cd2b91f38 --- /dev/null +++ b/tests/translator/input/websocket_api_auto_name.yaml @@ -0,0 +1,14 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_custom_domains_regional.yaml b/tests/translator/input/websocket_api_custom_domains_regional.yaml new file mode 100644 index 0000000000..367f4bff7e --- /dev/null +++ b/tests/translator/input/websocket_api_custom_domains_regional.yaml @@ -0,0 +1,50 @@ +Parameters: + MyDomainName: + Type: String + MyDomainCert: + Type: String + HostedZoneId: + Type: String + +Globals: + WebSocketApi: + Domain: + DomainName: + Ref: MyDomainName + CertificateArn: + Ref: MyDomainCert + EndpointConfiguration: REGIONAL + SecurityPolicy: TLS_1_2 + BasePath: + - /get + - /post + Route53: + HostedZoneId: + Ref: HostedZoneId + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async(event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt MyFunction.Arn + StageName: Prod + +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/websocket_api_description.yaml b/tests/translator/input/websocket_api_description.yaml new file mode 100644 index 0000000000..440fe011f6 --- /dev/null +++ b/tests/translator/input/websocket_api_description.yaml @@ -0,0 +1,17 @@ +Resources: + WebSocketApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: WebSocketApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + Description: Lorem Ipsum + + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.10 + Handler: index.handler + CodeUri: s3://bucket/key diff --git a/tests/translator/input/websocket_api_domain_globals.yaml b/tests/translator/input/websocket_api_domain_globals.yaml new file mode 100644 index 0000000000..24d75aa39e --- /dev/null +++ b/tests/translator/input/websocket_api_domain_globals.yaml @@ -0,0 +1,44 @@ +Globals: + WebSocketApi: + Domain: + DomainName: admin.one.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + +Resources: + Connect1: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Connect2: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Api1: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: Api1 + Routes: + $connect: + FunctionArn: !GetAtt Connect1.Arn + RouteSelectionExpression: $request.body.action + Api2: + Type: AWS::Serverless::WebSocketApi + Properties: + Domain: + DomainName: admin.two.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + Name: Api2 + Routes: + $connect: + FunctionArn: !GetAtt Connect2.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_explicit_stage.yaml b/tests/translator/input/websocket_api_explicit_stage.yaml new file mode 100644 index 0000000000..f5a9228117 --- /dev/null +++ b/tests/translator/input/websocket_api_explicit_stage.yaml @@ -0,0 +1,38 @@ +Parameters: + PayloadFormatVersion: + Default: '1.0' + Type: String + +Globals: + WebSocketApi: + RouteSettings: + $default: + DataTraceEnabled: true + ThrottlingBurstLimit: 100 + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + AccessLogSettings: + DestinationArn: arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName + Format: $context.requestId + Name: MyApi + StageName: Prod + StageVariables: + VarName: VarValue + RouteSettings: + $default: + LoggingLevel: INFO + ThrottlingBurstLimit: 300 + ThrottlingRateLimit: 0.7 + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn diff --git a/tests/translator/input/websocket_api_route_config.yaml b/tests/translator/input/websocket_api_route_config.yaml new file mode 100644 index 0000000000..42f5f84cf1 --- /dev/null +++ b/tests/translator/input/websocket_api_route_config.yaml @@ -0,0 +1,26 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + Routes: + $connect: + ApiKeyRequired: true + FunctionArn: !GetAtt ConnectFunction.Arn + IntegrationTimeout: 15000 + ModelSelectionExpression: foo1 + OperationName: Connect + RequestModels: + rq1: rp1 + rq2: rp2 + RequestParameters: + param1: v1 + param2: v2 + RouteResponseSelectionExpression: foo2 + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_simple.yaml b/tests/translator/input/websocket_api_simple.yaml new file mode 100644 index 0000000000..bd81173ff1 --- /dev/null +++ b/tests/translator/input/websocket_api_simple.yaml @@ -0,0 +1,15 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_simple_app.yaml b/tests/translator/input/websocket_api_simple_app.yaml new file mode 100644 index 0000000000..7396ee1b41 --- /dev/null +++ b/tests/translator/input/websocket_api_simple_app.yaml @@ -0,0 +1,197 @@ +# Based partially on a starter template found in an AWS WebSocket tutorial +Resources: + ConnectionsTable: + Type: AWS::Serverless::SimpleTable + Properties: + PrimaryKey: + Name: connectionId + Type: String + ProvisionedThroughput: + ReadCapacityUnits: 5 + WriteCapacityUnits: 5 + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + Environment: + Variables: + TABLE_NAME: !Ref ConnectionsTable + InlineCode: |- + const {DynamoDBClient} = require("@aws-sdk/client-dynamodb") + const {DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb") + exports.handler = async function(event) { + + const client = new DynamoDBClient({}); + const docClient = DynamoDBDocumentClient.from(client); + const command = new PutCommand({ + TableName: process.env.TABLE_NAME, + Item: { + connectionId: event.requestContext.connectionId, + }, + }); + + try { + await docClient.send(command) + } catch (err) { + console.log(err) + return { + statusCode: 500 + }; + } + return { + statusCode: 200, + }; + } + Handler: index.handler + Runtime: nodejs20.x + Policies: + - AmazonDynamoDBFullAccess + DisconnectFunction: + Type: AWS::Serverless::Function + Properties: + Environment: + Variables: + TABLE_NAME: !Ref ConnectionsTable + InlineCode: |- + const {DynamoDBClient} = require("@aws-sdk/client-dynamodb") + const {DynamoDBDocumentClient, DeleteCommand } = require("@aws-sdk/lib-dynamodb") + exports.handler = async function(event) { + + const client = new DynamoDBClient({}); + const docClient = DynamoDBDocumentClient.from(client); + const command = new DeleteCommand({ + TableName: process.env.TABLE_NAME, + Key: { + connectionId: event.requestContext.connectionId, + }, + }); + + try { + await docClient.send(command) + } catch (err) { + console.log(err) + return { + statusCode: 500 + }; + } + return { + statusCode: 200, + }; + } + Handler: index.handler + Runtime: nodejs20.x + Policies: + - AmazonDynamoDBFullAccess + SendFunction: + Type: AWS::Serverless::Function + Properties: + Environment: + Variables: + TABLE_NAME: !Ref ConnectionsTable + InlineCode: |- + const {DynamoDBClient} = require("@aws-sdk/client-dynamodb") + const {DynamoDBDocumentClient, ScanCommand } = require("@aws-sdk/lib-dynamodb") + const {ApiGatewayManagementApiClient, PostToConnectionCommand} = require("@aws-sdk/client-apigatewaymanagementapi") + exports.handler = async function(event) { + const client = new DynamoDBClient({}); + const docClient = DynamoDBDocumentClient.from(client); + const ddbcommand = new ScanCommand({ + TableName: process.env.TABLE_NAME + }) + + let connections; + try { connections = await docClient.send(ddbcommand); + } catch (err) { + console.log(err) + return { + statusCode: 500, + }; + } + + const callbackAPI = new ApiGatewayManagementApiClient({ + apiVersion: '2018-11-29', + endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage, + }); + + const message = JSON.parse(event.body).message; + + const sendMessages = connections.Items.map(async ({connectionId}) => { + if (connectionId !== event.requestContext.connectionId) { + try { + await callbackAPI.send(new PostToConnectionCommand( + { ConnectionId: connectionId, Data: message, } + )); + } catch (e) { + console.log(e); + } + } + }); + + try { + await Promise.all(sendMessages) + } catch (e) { + console.log(e); + return { + statusCode: 500, + }; + } + + return{statusCode: 200}; + }; + Handler: index.handler + Runtime: nodejs20.x + Policies: + - AmazonAPIGatewayInvokeFullAccess + - AmazonDynamoDBFullAccess + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: |- + const {ApiGatewayManagementApiClient, PostToConnectionCommand, GetConnectionCommand} = require("@aws-sdk/client-apigatewaymanagementapi") + exports.handler = async function(event) { + let connectionInfo; + let connectionId = event.requestContext.connectionId; + + const callbackAPI = new ApiGatewayManagementApiClient({ + apiVersion: '2018-11-29', + endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage + }); + + try { + connectionInfo = await callbackAPI.send(new GetConnectionCommand( + {ConnectionId: event.requestContext.connectionId } + )); + } catch (e) { + console.log(e); + } + + connectionInfo.connectionID = connectionId; + + await callbackAPI.send(new PostToConnectionCommand( + {ConnectionId: event.requestContext.connectionId, + Data: + 'Use the send route to send a message. Your info:' + + JSON.stringify(connectionInfo)} + )); + return { + statusCode: 200, + }; + }; + Handler: index.handler + Runtime: nodejs20.x + Policies: + - AmazonAPIGatewayInvokeFullAccess + - AmazonDynamoDBFullAccess + SimpleChatApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: SimpleChatApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + $disconnect: + FunctionArn: !GetAtt DisconnectFunction.Arn + send: + FunctionArn: !GetAtt SendFunction.Arn + $default: + FunctionArn: !GetAtt DefaultFunction.Arn diff --git a/tests/translator/input/websocket_api_stage_config.yaml b/tests/translator/input/websocket_api_stage_config.yaml new file mode 100644 index 0000000000..4b8522b398 --- /dev/null +++ b/tests/translator/input/websocket_api_stage_config.yaml @@ -0,0 +1,22 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + AccessLogSettings: + DestinationArn: foo + Format: $context.requestId + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + StageName: Prod + StageVariables: + var1: val1 + var2: val2 diff --git a/tests/translator/input/websocket_api_stage_globals.yaml b/tests/translator/input/websocket_api_stage_globals.yaml new file mode 100644 index 0000000000..7f04fd4e81 --- /dev/null +++ b/tests/translator/input/websocket_api_stage_globals.yaml @@ -0,0 +1,44 @@ +Globals: + WebSocketApi: + AccessLogSettings: + DestinationArn: arn1 + Format: $context.requestId + StageVariables: + var1: val1 + var2: val2 + +Resources: + Connect1: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Connect2: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + Api1: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: Api1 + Routes: + $connect: + FunctionArn: !GetAtt Connect1.Arn + RouteSelectionExpression: $request.body.action + Api2: + Type: AWS::Serverless::WebSocketApi + Properties: + AccessLogSettings: + DestinationArn: arn2 + Format: $context.requestId + StageVariables: + var2: val4 + var3: val3 + Name: Api2 + Routes: + $connect: + FunctionArn: !GetAtt Connect2.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_test_non_ref.yaml b/tests/translator/input/websocket_api_test_non_ref.yaml new file mode 100644 index 0000000000..d95822f619 --- /dev/null +++ b/tests/translator/input/websocket_api_test_non_ref.yaml @@ -0,0 +1,52 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + AuthArn: autharn + InvokeRole: rolearn + Name: MyApi + Routes: + $connect: + FunctionArn: connectphysid + RouteSelectionExpression: $request.body.action + MyAuth: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs12.x + RootRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - apigateway.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: root + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: '*' + Resource: '*' + RootInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Path: / + Roles: + - !Ref RootRole diff --git a/tests/translator/input/websocket_api_with_auth_config.yaml b/tests/translator/input/websocket_api_with_auth_config.yaml new file mode 100644 index 0000000000..468c2e95ed --- /dev/null +++ b/tests/translator/input/websocket_api_with_auth_config.yaml @@ -0,0 +1,28 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthArn: !GetAtt MyAuth.Arn + AuthType: CUSTOM + IdentitySource: + - idsource1 + - idsource2 + Name: test + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + MyAuth: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs12.x diff --git a/tests/translator/input/websocket_api_with_custom_domain_route53_multiple.yaml b/tests/translator/input/websocket_api_with_custom_domain_route53_multiple.yaml new file mode 100644 index 0000000000..7b10e0ba11 --- /dev/null +++ b/tests/translator/input/websocket_api_with_custom_domain_route53_multiple.yaml @@ -0,0 +1,61 @@ +Resources: + Connect1: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.10 + Handler: index1.handler + CodeUri: s3://bucket/key1 + Connect2: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.10 + Handler: index2.handler + CodeUri: s3://bucket/key2 + Connect3: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.10 + Handler: index3.handler + CodeUri: s3://bucket/key3 + Api1: + Type: AWS::Serverless::WebSocketApi + Properties: + Domain: + DomainName: admin.one.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + Name: Api1 + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt Connect1.Arn + Api2: + Type: AWS::Serverless::WebSocketApi + Properties: + Domain: + DomainName: admin.two.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + Name: Api2 + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt Connect2.Arn + Api3: + Type: AWS::Serverless::WebSocketApi + Properties: + Domain: + DomainName: admin.three.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + Name: Api3 + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt Connect3.Arn diff --git a/tests/translator/input/websocket_api_with_custom_domains_regional.yaml b/tests/translator/input/websocket_api_with_custom_domains_regional.yaml new file mode 100644 index 0000000000..5fbb62b084 --- /dev/null +++ b/tests/translator/input/websocket_api_with_custom_domains_regional.yaml @@ -0,0 +1,46 @@ +Parameters: + MyDomainName: + Type: String + MyDomainCert: + Type: String + HostedZoneId: + Type: String + +Globals: + WebSocketApi: + Domain: + DomainName: !Ref MyDomainName + CertificateArn: !Ref MyDomainCert + EndpointConfiguration: REGIONAL + SecurityPolicy: TLS_1_2 + BasePath: + - /get + - /post + Route53: + HostedZoneId: !Ref HostedZoneId + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs18.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt MyFunction.Arn + StageName: Prod +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing.yaml b/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing.yaml new file mode 100644 index 0000000000..41fce6358b --- /dev/null +++ b/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing.yaml @@ -0,0 +1,51 @@ +Parameters: + MyRestRegionalDomainName: + Type: String + MyRestRegionalDomainCert: + Type: String + HostedZoneId: + Type: String + +Globals: + WebSocketApi: + Domain: + DomainName: + Ref: MyRestRegionalDomainName + CertificateArn: + Ref: MyRestRegionalDomainCert + EndpointConfiguration: REGIONAL + SecurityPolicy: TLS_1_2 + BasePath: + - /get + - /post + Route53: + HostedZoneId: + Ref: HostedZoneId + Region: eu-west-2 + SetIdentifier: eu-west-2 + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs18.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing_ipv6.yaml b/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing_ipv6.yaml new file mode 100644 index 0000000000..5383f12106 --- /dev/null +++ b/tests/translator/input/websocket_api_with_custom_domains_regional_latency_routing_ipv6.yaml @@ -0,0 +1,52 @@ +Parameters: + MyRestRegionalDomainName: + Type: String + MyRestRegionalDomainCert: + Type: String + HostedZoneId: + Type: String + +Globals: + WebSocketApi: + Domain: + DomainName: + Ref: MyRestRegionalDomainName + CertificateArn: + Ref: MyRestRegionalDomainCert + EndpointConfiguration: REGIONAL + SecurityPolicy: TLS_1_2 + BasePath: + - /get + - /post + Route53: + HostedZoneId: + Ref: HostedZoneId + Region: eu-west-2 + SetIdentifier: eu-west-2 + IpV6: true + +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs18.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + RouteSelectionExpression: $request.body.action + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/websocket_api_with_iam_auth.yaml b/tests/translator/input/websocket_api_with_iam_auth.yaml new file mode 100644 index 0000000000..ff147d89c6 --- /dev/null +++ b/tests/translator/input/websocket_api_with_iam_auth.yaml @@ -0,0 +1,44 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Name: MyApi + Auth: + AuthType: AWS_IAM + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + RootRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - ec2.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: root + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: '*' + Resource: '*' + RootInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Path: / + Roles: + - !Ref RootRole diff --git a/tests/translator/input/websocket_api_with_lambda_auth.yaml b/tests/translator/input/websocket_api_with_lambda_auth.yaml new file mode 100644 index 0000000000..302729ba51 --- /dev/null +++ b/tests/translator/input/websocket_api_with_lambda_auth.yaml @@ -0,0 +1,24 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + AuthArn: !GetAtt MyAuth.Arn + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + MyAuth: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs12.x diff --git a/tests/translator/input/websocket_api_with_lambda_auth_invoke_role.yaml b/tests/translator/input/websocket_api_with_lambda_auth_invoke_role.yaml new file mode 100644 index 0000000000..18ff27692f --- /dev/null +++ b/tests/translator/input/websocket_api_with_lambda_auth_invoke_role.yaml @@ -0,0 +1,52 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: CUSTOM + AuthArn: !GetAtt MyAuth.Arn + InvokeRole: !GetAtt RootRole.Arn + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action + MyAuth: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs12.x + RootRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - apigateway.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: root + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: '*' + Resource: '*' + RootInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Path: / + Roles: + - !Ref RootRole diff --git a/tests/translator/input/websocket_api_with_none_auth.yaml b/tests/translator/input/websocket_api_with_none_auth.yaml new file mode 100644 index 0000000000..108bb22af3 --- /dev/null +++ b/tests/translator/input/websocket_api_with_none_auth.yaml @@ -0,0 +1,17 @@ +Resources: + ConnectFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: '# placeholder' + Handler: hello.handler + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + Auth: + AuthType: NONE + Name: MyApi + Routes: + $connect: + FunctionArn: !GetAtt ConnectFunction.Arn + RouteSelectionExpression: $request.body.action diff --git a/tests/translator/input/websocket_api_with_propagate_tags.yaml b/tests/translator/input/websocket_api_with_propagate_tags.yaml new file mode 100644 index 0000000000..6c15e4fd26 --- /dev/null +++ b/tests/translator/input/websocket_api_with_propagate_tags.yaml @@ -0,0 +1,41 @@ +Globals: + WebSocketApi: + RouteSettings: + $default: + DataTraceEnabled: true + ThrottlingBurstLimit: 100 +Resources: + DefaultFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: foo + Handler: bar + Runtime: nodejs20.x + MyApi: + Type: AWS::Serverless::WebSocketApi + Properties: + AccessLogSettings: + DestinationArn: random-arn + Format: $context.requestId + Domain: + DomainName: admin.one.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + PropagateTags: true + Name: MyApi + RouteSettings: + $default: + ThrottlingBurstLimit: 200 + ThrottlingRateLimit: 0.7 + RouteSelectionExpression: $request.body.action + Routes: + $default: + FunctionArn: !GetAtt DefaultFunction.Arn + StageName: Prod + StageVariables: + VarName: VarValue + Tags: + TagKey1: Value1 + TagKey2: Value2 diff --git a/tests/translator/output/aws-cn/websocket_api_api_config.json b/tests/translator/output/aws-cn/websocket_api_api_config.json new file mode 100644 index 0000000000..ca4069359f --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_api_config.json @@ -0,0 +1,142 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "IpAddressType": "dualstack", + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_api_globals.json b/tests/translator/output/aws-cn/websocket_api_api_globals.json new file mode 100644 index 0000000000..17e17397b3 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_api_globals.json @@ -0,0 +1,285 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "ApiKeySelectionExpression": "Integration.TemplateSelectionExpression", + "DisableExecuteApiEndpoint": false, + "DisableSchemaValidation": false, + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.message", + "Tags": { + "tag1": "val1", + "tag2": "val4", + "tag3": "val3", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_auto_name.json b/tests/translator/output/aws-cn/websocket_api_auto_name.json new file mode 100644 index 0000000000..10704dab57 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_auto_name.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_custom_domains_regional.json b/tests/translator/output/aws-cn/websocket_api_custom_domains_regional.json new file mode 100644 index 0000000000..500244f167 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async(event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_description.json b/tests/translator/output/aws-cn/websocket_api_description.json new file mode 100644 index 0000000000..cb3a35cf53 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_description.json @@ -0,0 +1,140 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "WebSocketApi": { + "Properties": { + "Description": "Lorem Ipsum", + "Name": "WebSocketApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "WebSocketApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "WebSocketApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "WebSocketApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "WebSocketApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "WebSocketApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_domain_globals.json b/tests/translator/output/aws-cn/websocket_api_domain_globals.json new file mode 100644 index 0000000000..277001cb58 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_domain_globals.json @@ -0,0 +1,356 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_explicit_stage.json b/tests/translator/output/aws-cn/websocket_api_explicit_stage.json new file mode 100644 index 0000000000..0c13194a5a --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_explicit_stage.json @@ -0,0 +1,163 @@ +{ + "Parameters": { + "PayloadFormatVersion": { + "Default": "1.0", + "Type": "String" + } + }, + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiConnectRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "LoggingLevel": "INFO", + "ThrottlingBurstLimit": 300, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_route_config.json b/tests/translator/output/aws-cn/websocket_api_route_config.json new file mode 100644 index 0000000000..bed2bd5e42 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_route_config.json @@ -0,0 +1,151 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + }, + "TimeoutInMillis": 15000 + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiKeyRequired": true, + "ModelSelectionExpression": "foo1", + "OperationName": "Connect", + "RequestModels": { + "rq1": "rp1", + "rq2": "rp2" + }, + "RequestParameters": { + "param1": "v1", + "param2": "v2" + }, + "RouteKey": "$connect", + "RouteResponseSelectionExpression": "foo2", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_simple.json b/tests/translator/output/aws-cn/websocket_api_simple.json new file mode 100644 index 0000000000..10704dab57 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_simple.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_simple_app.json b/tests/translator/output/aws-cn/websocket_api_simple_app.json new file mode 100644 index 0000000000..17feaad4fb --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_simple_app.json @@ -0,0 +1,516 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, PutCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new PutCommand({\n TableName: process.env.TABLE_NAME,\n Item: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ConnectionsTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "connectionId", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "connectionId", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "Type": "AWS::DynamoDB::Table" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "const {ApiGatewayManagementApiClient, PostToConnectionCommand, GetConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\n exports.handler = async function(event) {\n let connectionInfo;\n let connectionId = event.requestContext.connectionId;\n \n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage\n }); \n\n try {\n connectionInfo = await callbackAPI.send(new GetConnectionCommand(\n {ConnectionId: event.requestContext.connectionId }\n ));\n } catch (e) {\n console.log(e);\n }\n \n connectionInfo.connectionID = connectionId;\n \n await callbackAPI.send(new PostToConnectionCommand(\n {ConnectionId: event.requestContext.connectionId,\n Data:\n 'Use the send route to send a message. Your info:' +\n JSON.stringify(connectionInfo)}\n ));\n return {\n statusCode: 200,\n };\n };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "DisconnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, DeleteCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new DeleteCommand({\n TableName: process.env.TABLE_NAME,\n Key: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DisconnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DisconnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SendFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\nconst {DynamoDBDocumentClient, ScanCommand } = require(\"@aws-sdk/lib-dynamodb\")\nconst {ApiGatewayManagementApiClient, PostToConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\nexports.handler = async function(event) {\n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const ddbcommand = new ScanCommand({\n TableName: process.env.TABLE_NAME\n })\n\n let connections;\n try { connections = await docClient.send(ddbcommand);\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500,\n };\n }\n\n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage,\n });\n\n const message = JSON.parse(event.body).message;\n\n const sendMessages = connections.Items.map(async ({connectionId}) => {\n if (connectionId !== event.requestContext.connectionId) {\n try {\n await callbackAPI.send(new PostToConnectionCommand(\n { ConnectionId: connectionId, Data: message, }\n ));\n } catch (e) {\n console.log(e);\n }\n }\n });\n\n try {\n await Promise.all(sendMessages)\n } catch (e) {\n console.log(e);\n return {\n statusCode: 500,\n };\n }\n\n return{statusCode: 200};\n};" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SendFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "SendFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SimpleChatApi": { + "Properties": { + "Name": "SimpleChatApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "SimpleChatApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "SimpleChatApiDisconnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDisconnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$disconnect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDisconnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$disconnect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDisconnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiSendIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiSendPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/send" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiSendRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "send", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiSendIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_stage_config.json b/tests/translator/output/aws-cn/websocket_api_stage_config.json new file mode 100644 index 0000000000..214f659ae3 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_stage_config.json @@ -0,0 +1,146 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "foo", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_stage_globals.json b/tests/translator/output/aws-cn/websocket_api_stage_globals.json new file mode 100644 index 0000000000..a7ca91a787 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_stage_globals.json @@ -0,0 +1,289 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn1", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn2", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val4", + "var3": "val3" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_test_non_ref.json b/tests/translator/output/aws-cn/websocket_api_test_non_ref.json new file mode 100644 index 0000000000..596c04e303 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_test_non_ref.json @@ -0,0 +1,252 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": "rolearn", + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": "autharn" + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": "connectphysid" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": "connectphysid", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_auth_config.json b/tests/translator/output/aws-cn/websocket_api_with_auth_config.json new file mode 100644 index 0000000000..f463e866ad --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_auth_config.json @@ -0,0 +1,245 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "IdentitySource": [ + "idsource1", + "idsource2" + ], + "Name": "test" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_custom_domain_route53_multiple.json b/tests/translator/output/aws-cn/websocket_api_with_custom_domain_route53_multiple.json new file mode 100644 index 0000000000..f271ca99bf --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_custom_domain_route53_multiple.json @@ -0,0 +1,522 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api3": { + "Properties": { + "Name": "Api3", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api3ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV241bfc7f9c4" + }, + "Stage": { + "Ref": "Api3DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api3ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api3ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api3.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api3ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api3ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api3DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV241bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key1" + }, + "Handler": "index1.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key2" + }, + "Handler": "index2.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "Connect3": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key3" + }, + "Handler": "index3.handler", + "Role": { + "Fn::GetAtt": [ + "Connect3Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect3Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional.json b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional.json new file mode 100644 index 0000000000..bb32b7579d --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing.json b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing.json new file mode 100644 index 0000000000..2f038207b4 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing.json @@ -0,0 +1,234 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json new file mode 100644 index 0000000000..7810831ea4 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json @@ -0,0 +1,256 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + }, + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "AAAA" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_iam_auth.json b/tests/translator/output/aws-cn/websocket_api_with_iam_auth.json new file mode 100644 index 0000000000..6a28fcd72a --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_iam_auth.json @@ -0,0 +1,187 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "AWS_IAM", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "ec2.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_lambda_auth.json b/tests/translator/output/aws-cn/websocket_api_with_lambda_auth.json new file mode 100644 index 0000000000..9cd1d0d515 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_lambda_auth.json @@ -0,0 +1,241 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_lambda_auth_invoke_role.json b/tests/translator/output/aws-cn/websocket_api_with_lambda_auth_invoke_role.json new file mode 100644 index 0000000000..459d8848aa --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_lambda_auth_invoke_role.json @@ -0,0 +1,272 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": { + "Fn::GetAtt": [ + "RootRole", + "Arn" + ] + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_none_auth.json b/tests/translator/output/aws-cn/websocket_api_with_none_auth.json new file mode 100644 index 0000000000..cb7b83043f --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_none_auth.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "NONE", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/websocket_api_with_propagate_tags.json b/tests/translator/output/aws-cn/websocket_api_with_propagate_tags.json new file mode 100644 index 0000000000..050a80a359 --- /dev/null +++ b/tests/translator/output/aws-cn/websocket_api_with_propagate_tags.json @@ -0,0 +1,216 @@ +{ + "Resources": { + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Handler": "bar", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiDefaultRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "random-arn", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 200, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_api_config.json b/tests/translator/output/aws-us-gov/websocket_api_api_config.json new file mode 100644 index 0000000000..3fc70050f3 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_api_config.json @@ -0,0 +1,142 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "IpAddressType": "dualstack", + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_api_globals.json b/tests/translator/output/aws-us-gov/websocket_api_api_globals.json new file mode 100644 index 0000000000..9918b6b847 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_api_globals.json @@ -0,0 +1,285 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "ApiKeySelectionExpression": "Integration.TemplateSelectionExpression", + "DisableExecuteApiEndpoint": false, + "DisableSchemaValidation": false, + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.message", + "Tags": { + "tag1": "val1", + "tag2": "val4", + "tag3": "val3", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_auto_name.json b/tests/translator/output/aws-us-gov/websocket_api_auto_name.json new file mode 100644 index 0000000000..f122b066b9 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_auto_name.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_custom_domains_regional.json b/tests/translator/output/aws-us-gov/websocket_api_custom_domains_regional.json new file mode 100644 index 0000000000..6fddbad029 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async(event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_description.json b/tests/translator/output/aws-us-gov/websocket_api_description.json new file mode 100644 index 0000000000..81231327d0 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_description.json @@ -0,0 +1,140 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "WebSocketApi": { + "Properties": { + "Description": "Lorem Ipsum", + "Name": "WebSocketApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "WebSocketApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "WebSocketApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "WebSocketApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "WebSocketApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "WebSocketApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_domain_globals.json b/tests/translator/output/aws-us-gov/websocket_api_domain_globals.json new file mode 100644 index 0000000000..2febb5012e --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_domain_globals.json @@ -0,0 +1,356 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_explicit_stage.json b/tests/translator/output/aws-us-gov/websocket_api_explicit_stage.json new file mode 100644 index 0000000000..30edb15b92 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_explicit_stage.json @@ -0,0 +1,163 @@ +{ + "Parameters": { + "PayloadFormatVersion": { + "Default": "1.0", + "Type": "String" + } + }, + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiConnectRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "LoggingLevel": "INFO", + "ThrottlingBurstLimit": 300, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_route_config.json b/tests/translator/output/aws-us-gov/websocket_api_route_config.json new file mode 100644 index 0000000000..500703fc55 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_route_config.json @@ -0,0 +1,151 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + }, + "TimeoutInMillis": 15000 + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiKeyRequired": true, + "ModelSelectionExpression": "foo1", + "OperationName": "Connect", + "RequestModels": { + "rq1": "rp1", + "rq2": "rp2" + }, + "RequestParameters": { + "param1": "v1", + "param2": "v2" + }, + "RouteKey": "$connect", + "RouteResponseSelectionExpression": "foo2", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_simple.json b/tests/translator/output/aws-us-gov/websocket_api_simple.json new file mode 100644 index 0000000000..f122b066b9 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_simple.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_simple_app.json b/tests/translator/output/aws-us-gov/websocket_api_simple_app.json new file mode 100644 index 0000000000..79a3c7b5b4 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_simple_app.json @@ -0,0 +1,516 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, PutCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new PutCommand({\n TableName: process.env.TABLE_NAME,\n Item: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ConnectionsTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "connectionId", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "connectionId", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "Type": "AWS::DynamoDB::Table" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "const {ApiGatewayManagementApiClient, PostToConnectionCommand, GetConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\n exports.handler = async function(event) {\n let connectionInfo;\n let connectionId = event.requestContext.connectionId;\n \n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage\n }); \n\n try {\n connectionInfo = await callbackAPI.send(new GetConnectionCommand(\n {ConnectionId: event.requestContext.connectionId }\n ));\n } catch (e) {\n console.log(e);\n }\n \n connectionInfo.connectionID = connectionId;\n \n await callbackAPI.send(new PostToConnectionCommand(\n {ConnectionId: event.requestContext.connectionId,\n Data:\n 'Use the send route to send a message. Your info:' +\n JSON.stringify(connectionInfo)}\n ));\n return {\n statusCode: 200,\n };\n };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "DisconnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, DeleteCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new DeleteCommand({\n TableName: process.env.TABLE_NAME,\n Key: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DisconnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DisconnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SendFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\nconst {DynamoDBDocumentClient, ScanCommand } = require(\"@aws-sdk/lib-dynamodb\")\nconst {ApiGatewayManagementApiClient, PostToConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\nexports.handler = async function(event) {\n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const ddbcommand = new ScanCommand({\n TableName: process.env.TABLE_NAME\n })\n\n let connections;\n try { connections = await docClient.send(ddbcommand);\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500,\n };\n }\n\n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage,\n });\n\n const message = JSON.parse(event.body).message;\n\n const sendMessages = connections.Items.map(async ({connectionId}) => {\n if (connectionId !== event.requestContext.connectionId) {\n try {\n await callbackAPI.send(new PostToConnectionCommand(\n { ConnectionId: connectionId, Data: message, }\n ));\n } catch (e) {\n console.log(e);\n }\n }\n });\n\n try {\n await Promise.all(sendMessages)\n } catch (e) {\n console.log(e);\n return {\n statusCode: 500,\n };\n }\n\n return{statusCode: 200};\n};" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SendFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "SendFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SimpleChatApi": { + "Properties": { + "Name": "SimpleChatApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "SimpleChatApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "SimpleChatApiDisconnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDisconnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$disconnect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDisconnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$disconnect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDisconnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiSendIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiSendPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/send" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiSendRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "send", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiSendIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_stage_config.json b/tests/translator/output/aws-us-gov/websocket_api_stage_config.json new file mode 100644 index 0000000000..acf233a153 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_stage_config.json @@ -0,0 +1,146 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "foo", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_stage_globals.json b/tests/translator/output/aws-us-gov/websocket_api_stage_globals.json new file mode 100644 index 0000000000..7f4e6bd0ce --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_stage_globals.json @@ -0,0 +1,289 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn1", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn2", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val4", + "var3": "val3" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_test_non_ref.json b/tests/translator/output/aws-us-gov/websocket_api_test_non_ref.json new file mode 100644 index 0000000000..eac829bccf --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_test_non_ref.json @@ -0,0 +1,252 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": "rolearn", + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": "autharn" + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": "connectphysid" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": "connectphysid", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_auth_config.json b/tests/translator/output/aws-us-gov/websocket_api_with_auth_config.json new file mode 100644 index 0000000000..f96abcc56b --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_auth_config.json @@ -0,0 +1,245 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "IdentitySource": [ + "idsource1", + "idsource2" + ], + "Name": "test" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_custom_domain_route53_multiple.json b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domain_route53_multiple.json new file mode 100644 index 0000000000..496a7a673c --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domain_route53_multiple.json @@ -0,0 +1,522 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api3": { + "Properties": { + "Name": "Api3", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api3ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV241bfc7f9c4" + }, + "Stage": { + "Ref": "Api3DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api3ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api3ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api3.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api3ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api3ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api3DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV241bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key1" + }, + "Handler": "index1.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key2" + }, + "Handler": "index2.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "Connect3": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key3" + }, + "Handler": "index3.handler", + "Role": { + "Fn::GetAtt": [ + "Connect3Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect3Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional.json b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional.json new file mode 100644 index 0000000000..4a073c7ac2 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing.json b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing.json new file mode 100644 index 0000000000..a645269746 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing.json @@ -0,0 +1,234 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json new file mode 100644 index 0000000000..e65904b107 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json @@ -0,0 +1,256 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + }, + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "AAAA" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_iam_auth.json b/tests/translator/output/aws-us-gov/websocket_api_with_iam_auth.json new file mode 100644 index 0000000000..ac714889ae --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_iam_auth.json @@ -0,0 +1,187 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "AWS_IAM", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "ec2.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_lambda_auth.json b/tests/translator/output/aws-us-gov/websocket_api_with_lambda_auth.json new file mode 100644 index 0000000000..b08c9ad056 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_lambda_auth.json @@ -0,0 +1,241 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_lambda_auth_invoke_role.json b/tests/translator/output/aws-us-gov/websocket_api_with_lambda_auth_invoke_role.json new file mode 100644 index 0000000000..0f10ecc3f9 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_lambda_auth_invoke_role.json @@ -0,0 +1,272 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": { + "Fn::GetAtt": [ + "RootRole", + "Arn" + ] + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_none_auth.json b/tests/translator/output/aws-us-gov/websocket_api_with_none_auth.json new file mode 100644 index 0000000000..b183b79d2e --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_none_auth.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "NONE", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/websocket_api_with_propagate_tags.json b/tests/translator/output/aws-us-gov/websocket_api_with_propagate_tags.json new file mode 100644 index 0000000000..b1ffe6b574 --- /dev/null +++ b/tests/translator/output/aws-us-gov/websocket_api_with_propagate_tags.json @@ -0,0 +1,216 @@ +{ + "Resources": { + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Handler": "bar", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiDefaultRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "random-arn", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 200, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/error_globals_unsupported_type.json b/tests/translator/output/error_globals_unsupported_type.json index 31f2405042..7785908237 100644 --- a/tests/translator/output/error_globals_unsupported_type.json +++ b/tests/translator/output/error_globals_unsupported_type.json @@ -4,12 +4,12 @@ "Number of errors found: 1. ", "'Globals' section is invalid. ", "'NewType' is not supported. ", - "Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine']" + "Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine', 'WebSocketApi']" ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'NewType' is not supported. Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine']", + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'NewType' is not supported. Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine', 'WebSocketApi']", "errors": [ { - "errorMessage": "'Globals' section is invalid. 'NewType' is not supported. Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine']" + "errorMessage": "'Globals' section is invalid. 'NewType' is not supported. Must be one of the following values - ['Api', 'CapacityProvider', 'Function', 'HttpApi', 'LayerVersion', 'SimpleTable', 'StateMachine', 'WebSocketApi']" } ] } diff --git a/tests/translator/output/error_websocket_api_auth_no_connect.json b/tests/translator/output/error_websocket_api_auth_no_connect.json new file mode 100644 index 0000000000..778c4ab482 --- /dev/null +++ b/tests/translator/output/error_websocket_api_auth_no_connect.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Authorization is only available if there is a $connect route." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Authorization is only available if there is a $connect route.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Authorization is only available if there is a $connect route." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_authid_no_authtype.json b/tests/translator/output/error_websocket_api_authid_no_authtype.json new file mode 100644 index 0000000000..a4e08fcf6b --- /dev/null +++ b/tests/translator/output/error_websocket_api_authid_no_authtype.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "AuthType must be specified for additional auth configurations." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. AuthType must be specified for additional auth configurations.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. AuthType must be specified for additional auth configurations." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_authid_none_auth.json b/tests/translator/output/error_websocket_api_authid_none_auth.json new file mode 100644 index 0000000000..5e5fe924a6 --- /dev/null +++ b/tests/translator/output/error_websocket_api_authid_none_auth.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "No additional configurations supported for AuthType NONE." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. No additional configurations supported for AuthType NONE.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. No additional configurations supported for AuthType NONE." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_authtype_no_authid.json b/tests/translator/output/error_websocket_api_authtype_no_authid.json new file mode 100644 index 0000000000..27669a535c --- /dev/null +++ b/tests/translator/output/error_websocket_api_authtype_no_authid.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "AuthArn must be specified if AuthType is CUSTOM." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. AuthArn must be specified if AuthType is CUSTOM.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. AuthArn must be specified if AuthType is CUSTOM." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_config_no_auth.json b/tests/translator/output/error_websocket_api_config_no_auth.json new file mode 100644 index 0000000000..80cb30cf9a --- /dev/null +++ b/tests/translator/output/error_websocket_api_config_no_auth.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "AuthType must be specified for additional auth configurations." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. AuthType must be specified for additional auth configurations.", + "errors": [ + { + "errorMessage": "AuthType must be specified for additional auth configurations." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_empty_routes.json b/tests/translator/output/error_websocket_api_empty_routes.json new file mode 100644 index 0000000000..727f7d4120 --- /dev/null +++ b/tests/translator/output/error_websocket_api_empty_routes.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "WebSocket API must have at least one route." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. WebSocket API must have at least one route.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. WebSocket API must have at least one route." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_iam_auth_config.json b/tests/translator/output/error_websocket_api_iam_auth_config.json new file mode 100644 index 0000000000..4841dfd7e0 --- /dev/null +++ b/tests/translator/output/error_websocket_api_iam_auth_config.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "No additional configurations supported for AuthType AWS_IAM." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. No additional configurations supported for AuthType AWS_IAM.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. No additional configurations supported for AuthType AWS_IAM." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_invalid_authtype.json b/tests/translator/output/error_websocket_api_invalid_authtype.json new file mode 100644 index 0000000000..c4917981fa --- /dev/null +++ b/tests/translator/output/error_websocket_api_invalid_authtype.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "AuthType is not one of AWS_IAM, CUSTOM or NONE." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. AuthType is not one of AWS_IAM, CUSTOM or NONE.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. AuthType is not one of AWS_IAM, CUSTOM or NONE." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_invalid_basepath_type.json b/tests/translator/output/error_websocket_api_invalid_basepath_type.json new file mode 100644 index 0000000000..2f405858df --- /dev/null +++ b/tests/translator/output/error_websocket_api_invalid_basepath_type.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Basepath must be a string." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Basepath must be a string.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Basepath must be a string." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_invalid_ip_address_type.json b/tests/translator/output/error_websocket_api_invalid_ip_address_type.json new file mode 100644 index 0000000000..b9e34ae5ec --- /dev/null +++ b/tests/translator/output/error_websocket_api_invalid_ip_address_type.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "IpAddressType must be 'ipv4' or 'dualstack'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. IpAddressType must be 'ipv4' or 'dualstack'.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. IpAddressType must be 'ipv4' or 'dualstack'." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_invalid_route_name.json b/tests/translator/output/error_websocket_api_invalid_route_name.json new file mode 100644 index 0000000000..11d858ead1 --- /dev/null +++ b/tests/translator/output/error_websocket_api_invalid_route_name.json @@ -0,0 +1,15 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Route key '$nonsense' must be alphanumeric. ", + "Only $connect, $disconnect, and $default special routes are supported." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Route key '$nonsense' must be alphanumeric. Only $connect, $disconnect, and $default special routes are supported.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Route key '$nonsense' must be alphanumeric. Only $connect, $disconnect, and $default special routes are supported." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_invalid_stage_name.json b/tests/translator/output/error_websocket_api_invalid_stage_name.json new file mode 100644 index 0000000000..a3a051956d --- /dev/null +++ b/tests/translator/output/error_websocket_api_invalid_stage_name.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Stages cannot be named $default for WebSocket APIs." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Stages cannot be named $default for WebSocket APIs.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Stages cannot be named $default for WebSocket APIs." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_list_access_log_settings.json b/tests/translator/output/error_websocket_api_list_access_log_settings.json new file mode 100644 index 0000000000..202d8a86e6 --- /dev/null +++ b/tests/translator/output/error_websocket_api_list_access_log_settings.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Property 'AccessLogSettings' should be a map." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Property 'AccessLogSettings' should be a map.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Property 'AccessLogSettings' should be a map." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_list_default_route_settings.json b/tests/translator/output/error_websocket_api_list_default_route_settings.json new file mode 100644 index 0000000000..06b21b9208 --- /dev/null +++ b/tests/translator/output/error_websocket_api_list_default_route_settings.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Property 'DefaultRouteSettings' should be a map." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Property 'DefaultRouteSettings' should be a map.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Property 'DefaultRouteSettings' should be a map." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_list_route_settings.json b/tests/translator/output/error_websocket_api_list_route_settings.json new file mode 100644 index 0000000000..a841ff4c83 --- /dev/null +++ b/tests/translator/output/error_websocket_api_list_route_settings.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Property 'RouteSettings' should be a map." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Property 'RouteSettings' should be a map.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Property 'RouteSettings' should be a map." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_no_route_selection_expression.json b/tests/translator/output/error_websocket_api_no_route_selection_expression.json new file mode 100644 index 0000000000..6edcef51f6 --- /dev/null +++ b/tests/translator/output/error_websocket_api_no_route_selection_expression.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Missing required property 'RouteSelectionExpression'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Missing required property 'RouteSelectionExpression'.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Missing required property 'RouteSelectionExpression'." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_no_routes.json b/tests/translator/output/error_websocket_api_no_routes.json new file mode 100644 index 0000000000..f6593a4eb5 --- /dev/null +++ b/tests/translator/output/error_websocket_api_no_routes.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Missing required property 'Routes'." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Missing required property 'Routes'.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Missing required property 'Routes'." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_non_connect_request_parameters.json b/tests/translator/output/error_websocket_api_non_connect_request_parameters.json new file mode 100644 index 0000000000..40a7590d46 --- /dev/null +++ b/tests/translator/output/error_websocket_api_non_connect_request_parameters.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Request parameters are only supported for the $connect route in WebSocket APIs." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Request parameters are only supported for the $connect route in WebSocket APIs.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Request parameters are only supported for the $connect route in WebSocket APIs." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_none_auth_config.json b/tests/translator/output/error_websocket_api_none_auth_config.json new file mode 100644 index 0000000000..5e5fe924a6 --- /dev/null +++ b/tests/translator/output/error_websocket_api_none_auth_config.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "No additional configurations supported for AuthType NONE." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. No additional configurations supported for AuthType NONE.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. No additional configurations supported for AuthType NONE." + } + ] +} diff --git a/tests/translator/output/error_websocket_api_route_no_function.json b/tests/translator/output/error_websocket_api_route_no_function.json new file mode 100644 index 0000000000..5d94b8e1d5 --- /dev/null +++ b/tests/translator/output/error_websocket_api_route_no_function.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [WSApi] is invalid. ", + "Route must have associated function." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [WSApi] is invalid. Route must have associated function.", + "errors": [ + { + "errorMessage": "Resource with id [WSApi] is invalid. Route must have associated function." + } + ] +} diff --git a/tests/translator/output/websocket_api_api_config.json b/tests/translator/output/websocket_api_api_config.json new file mode 100644 index 0000000000..a1305ee4b1 --- /dev/null +++ b/tests/translator/output/websocket_api_api_config.json @@ -0,0 +1,142 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "IpAddressType": "dualstack", + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_api_globals.json b/tests/translator/output/websocket_api_api_globals.json new file mode 100644 index 0000000000..0845e692d2 --- /dev/null +++ b/tests/translator/output/websocket_api_api_globals.json @@ -0,0 +1,285 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "ApiKeySelectionExpression": "Api.RouteSelectionExpression", + "DisableExecuteApiEndpoint": true, + "DisableSchemaValidation": true, + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "tag1": "val1", + "tag2": "val2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "ApiKeySelectionExpression": "Integration.TemplateSelectionExpression", + "DisableExecuteApiEndpoint": false, + "DisableSchemaValidation": false, + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.message", + "Tags": { + "tag1": "val1", + "tag2": "val4", + "tag3": "val3", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_auto_name.json b/tests/translator/output/websocket_api_auto_name.json new file mode 100644 index 0000000000..64300b0896 --- /dev/null +++ b/tests/translator/output/websocket_api_auto_name.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_custom_domains_regional.json b/tests/translator/output/websocket_api_custom_domains_regional.json new file mode 100644 index 0000000000..2714a58d0d --- /dev/null +++ b/tests/translator/output/websocket_api_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async(event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_description.json b/tests/translator/output/websocket_api_description.json new file mode 100644 index 0000000000..fe0c1f15eb --- /dev/null +++ b/tests/translator/output/websocket_api_description.json @@ -0,0 +1,140 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "WebSocketApi": { + "Properties": { + "Description": "Lorem Ipsum", + "Name": "WebSocketApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "WebSocketApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "WebSocketApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "WebSocketApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "WebSocketApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "WebSocketApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "WebSocketApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_domain_globals.json b/tests/translator/output/websocket_api_domain_globals.json new file mode 100644 index 0000000000..54d7a467d1 --- /dev/null +++ b/tests/translator/output/websocket_api_domain_globals.json @@ -0,0 +1,356 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV23fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_explicit_stage.json b/tests/translator/output/websocket_api_explicit_stage.json new file mode 100644 index 0000000000..4df5e3da17 --- /dev/null +++ b/tests/translator/output/websocket_api_explicit_stage.json @@ -0,0 +1,163 @@ +{ + "Parameters": { + "PayloadFormatVersion": { + "Default": "1.0", + "Type": "String" + } + }, + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiConnectRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "LoggingLevel": "INFO", + "ThrottlingBurstLimit": 300, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_route_config.json b/tests/translator/output/websocket_api_route_config.json new file mode 100644 index 0000000000..efd1b6d296 --- /dev/null +++ b/tests/translator/output/websocket_api_route_config.json @@ -0,0 +1,151 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + }, + "TimeoutInMillis": 15000 + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiKeyRequired": true, + "ModelSelectionExpression": "foo1", + "OperationName": "Connect", + "RequestModels": { + "rq1": "rp1", + "rq2": "rp2" + }, + "RequestParameters": { + "param1": "v1", + "param2": "v2" + }, + "RouteKey": "$connect", + "RouteResponseSelectionExpression": "foo2", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_simple.json b/tests/translator/output/websocket_api_simple.json new file mode 100644 index 0000000000..64300b0896 --- /dev/null +++ b/tests/translator/output/websocket_api_simple.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_simple_app.json b/tests/translator/output/websocket_api_simple_app.json new file mode 100644 index 0000000000..ed395e24a7 --- /dev/null +++ b/tests/translator/output/websocket_api_simple_app.json @@ -0,0 +1,516 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, PutCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new PutCommand({\n TableName: process.env.TABLE_NAME,\n Item: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "ConnectionsTable": { + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "connectionId", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "connectionId", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "Type": "AWS::DynamoDB::Table" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "const {ApiGatewayManagementApiClient, PostToConnectionCommand, GetConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\n exports.handler = async function(event) {\n let connectionInfo;\n let connectionId = event.requestContext.connectionId;\n \n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage\n }); \n\n try {\n connectionInfo = await callbackAPI.send(new GetConnectionCommand(\n {ConnectionId: event.requestContext.connectionId }\n ));\n } catch (e) {\n console.log(e);\n }\n \n connectionInfo.connectionID = connectionId;\n \n await callbackAPI.send(new PostToConnectionCommand(\n {ConnectionId: event.requestContext.connectionId,\n Data:\n 'Use the send route to send a message. Your info:' +\n JSON.stringify(connectionInfo)}\n ));\n return {\n statusCode: 200,\n };\n };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "DisconnectFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\n const {DynamoDBDocumentClient, DeleteCommand } = require(\"@aws-sdk/lib-dynamodb\")\n exports.handler = async function(event) {\n \n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const command = new DeleteCommand({\n TableName: process.env.TABLE_NAME,\n Key: {\n connectionId: event.requestContext.connectionId,\n },\n });\n \n try {\n await docClient.send(command)\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500\n };\n }\n return {\n statusCode: 200,\n };\n }" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DisconnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DisconnectFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SendFunction": { + "Properties": { + "Code": { + "ZipFile": "const {DynamoDBClient} = require(\"@aws-sdk/client-dynamodb\")\nconst {DynamoDBDocumentClient, ScanCommand } = require(\"@aws-sdk/lib-dynamodb\")\nconst {ApiGatewayManagementApiClient, PostToConnectionCommand} = require(\"@aws-sdk/client-apigatewaymanagementapi\")\nexports.handler = async function(event) {\n const client = new DynamoDBClient({});\n const docClient = DynamoDBDocumentClient.from(client);\n const ddbcommand = new ScanCommand({\n TableName: process.env.TABLE_NAME\n })\n\n let connections;\n try { connections = await docClient.send(ddbcommand);\n } catch (err) {\n console.log(err)\n return {\n statusCode: 500,\n };\n }\n\n const callbackAPI = new ApiGatewayManagementApiClient({\n apiVersion: '2018-11-29',\n endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage,\n });\n\n const message = JSON.parse(event.body).message;\n\n const sendMessages = connections.Items.map(async ({connectionId}) => {\n if (connectionId !== event.requestContext.connectionId) {\n try {\n await callbackAPI.send(new PostToConnectionCommand(\n { ConnectionId: connectionId, Data: message, }\n ));\n } catch (e) {\n console.log(e);\n }\n }\n });\n\n try {\n await Promise.all(sendMessages)\n } catch (e) {\n console.log(e);\n return {\n statusCode: 500,\n };\n }\n\n return{statusCode: 200};\n};" + }, + "Environment": { + "Variables": { + "TABLE_NAME": { + "Ref": "ConnectionsTable" + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SendFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "SendFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess", + "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "SimpleChatApi": { + "Properties": { + "Name": "SimpleChatApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "SimpleChatApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "SimpleChatApiDisconnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiDisconnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DisconnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/$disconnect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiDisconnectRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "$disconnect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiDisconnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "SimpleChatApiSendIntegration": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "SimpleChatApiSendPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "SendFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SimpleChatApi.ApiId}/default/send" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "SimpleChatApiSendRoute": { + "Properties": { + "ApiId": { + "Ref": "SimpleChatApi" + }, + "RouteKey": "send", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "SimpleChatApiSendIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + } + } +} diff --git a/tests/translator/output/websocket_api_stage_config.json b/tests/translator/output/websocket_api_stage_config.json new file mode 100644 index 0000000000..9f685005fb --- /dev/null +++ b/tests/translator/output/websocket_api_stage_config.json @@ -0,0 +1,146 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "foo", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_stage_globals.json b/tests/translator/output/websocket_api_stage_globals.json new file mode 100644 index 0000000000..ed7b1db4d1 --- /dev/null +++ b/tests/translator/output/websocket_api_stage_globals.json @@ -0,0 +1,289 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn1", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val2" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "AccessLogSettings": { + "DestinationArn": "arn2", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "StageVariables": { + "var1": "val1", + "var2": "val4", + "var3": "val3" + }, + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Connect1": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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/websocket_api_test_non_ref.json b/tests/translator/output/websocket_api_test_non_ref.json new file mode 100644 index 0000000000..cecb06128c --- /dev/null +++ b/tests/translator/output/websocket_api_test_non_ref.json @@ -0,0 +1,252 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": "rolearn", + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": "autharn" + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": "connectphysid" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": "connectphysid", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/websocket_api_with_auth_config.json b/tests/translator/output/websocket_api_with_auth_config.json new file mode 100644 index 0000000000..aa57ab5b9a --- /dev/null +++ b/tests/translator/output/websocket_api_with_auth_config.json @@ -0,0 +1,245 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "IdentitySource": [ + "idsource1", + "idsource2" + ], + "Name": "test" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_custom_domain_route53_multiple.json b/tests/translator/output/websocket_api_with_custom_domain_route53_multiple.json new file mode 100644 index 0000000000..97cfd2abee --- /dev/null +++ b/tests/translator/output/websocket_api_with_custom_domain_route53_multiple.json @@ -0,0 +1,522 @@ +{ + "Resources": { + "Api1": { + "Properties": { + "Name": "Api1", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api1ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "Api1DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api1ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api1ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect1", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api1.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api1ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api1ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api1DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api1" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api2": { + "Properties": { + "Name": "Api2", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api2ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV23fd2dbd8f8" + }, + "Stage": { + "Ref": "Api2DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api2ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api2ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect2", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api2.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api2ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api2ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api2DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api2" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "Api3": { + "Properties": { + "Name": "Api3", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "Api3ApiMapping": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV241bfc7f9c4" + }, + "Stage": { + "Ref": "Api3DefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "Api3ConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "Api3ConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Connect3", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${Api3.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "Api3ConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "Api3ConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "Api3DefaultStage": { + "Properties": { + "ApiId": { + "Ref": "Api3" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "ApiGatewayDomainNameV23fd2dbd8f8": { + "Properties": { + "DomainName": "admin.two.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV241bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "Connect1": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key1" + }, + "Handler": "index1.handler", + "Role": { + "Fn::GetAtt": [ + "Connect1Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect1Role": { + "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" + }, + "Connect2": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key2" + }, + "Handler": "index2.handler", + "Role": { + "Fn::GetAtt": [ + "Connect2Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect2Role": { + "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" + }, + "Connect3": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key3" + }, + "Handler": "index3.handler", + "Role": { + "Fn::GetAtt": [ + "Connect3Role", + "Arn" + ] + }, + "Runtime": "python3.10", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "Connect3Role": { + "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" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV241bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_with_custom_domains_regional.json b/tests/translator/output/websocket_api_with_custom_domains_regional.json new file mode 100644 index 0000000000..4540f278eb --- /dev/null +++ b/tests/translator/output/websocket_api_with_custom_domains_regional.json @@ -0,0 +1,232 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyDomainCert": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "Prod", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "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" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV2e12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing.json b/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing.json new file mode 100644 index 0000000000..2c6ae7e25d --- /dev/null +++ b/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing.json @@ -0,0 +1,234 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json b/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json new file mode 100644 index 0000000000..edde463ac8 --- /dev/null +++ b/tests/translator/output/websocket_api_with_custom_domains_regional_latency_routing_ipv6.json @@ -0,0 +1,256 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyRestRegionalDomainCert": { + "Type": "String" + }, + "MyRestRegionalDomainName": { + "Type": "String" + } + }, + "Resources": { + "ApiGatewayDomainNameV21a01391c0c": { + "Properties": { + "DomainName": { + "Ref": "MyRestRegionalDomainName" + }, + "DomainNameConfigurations": [ + { + "CertificateArn": { + "Ref": "MyRestRegionalDomainCert" + }, + "EndpointType": "REGIONAL", + "SecurityPolicy": "TLS_1_2" + } + ], + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n const response = {\n statusCode: 200,\n body: JSON.stringify('Hello from Lambda!'),\n };\n return response;\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyApigetApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "get", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApipostApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "ApiMappingKey": "post", + "DomainName": { + "Ref": "ApiGatewayDomainNameV21a01391c0c" + }, + "Stage": { + "Ref": "MyApiDefaultStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "A" + }, + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV21a01391c0c", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyRestRegionalDomainName" + }, + "Region": "eu-west-2", + "SetIdentifier": "eu-west-2", + "Type": "AAAA" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/websocket_api_with_iam_auth.json b/tests/translator/output/websocket_api_with_iam_auth.json new file mode 100644 index 0000000000..3c98fff14e --- /dev/null +++ b/tests/translator/output/websocket_api_with_iam_auth.json @@ -0,0 +1,187 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "AWS_IAM", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "ec2.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/websocket_api_with_lambda_auth.json b/tests/translator/output/websocket_api_with_lambda_auth.json new file mode 100644 index 0000000000..0949700759 --- /dev/null +++ b/tests/translator/output/websocket_api_with_lambda_auth.json @@ -0,0 +1,241 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiAuthorizerPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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/websocket_api_with_lambda_auth_invoke_role.json b/tests/translator/output/websocket_api_with_lambda_auth_invoke_role.json new file mode 100644 index 0000000000..b954b2b3ab --- /dev/null +++ b/tests/translator/output/websocket_api_with_lambda_auth_invoke_role.json @@ -0,0 +1,272 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectAuthorizer": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizerCredentialsArn": { + "Fn::GetAtt": [ + "RootRole", + "Arn" + ] + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthArn}/invocations", + { + "AuthArn": { + "Fn::GetAtt": [ + "MyAuth", + "Arn" + ] + } + } + ] + }, + "Name": "MyApiConnectAuthorizer" + }, + "Type": "AWS::ApiGatewayV2::Authorizer" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "MyApiConnectAuthorizer" + }, + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuth": { + "Properties": { + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyAuthRole", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthRole": { + "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" + }, + "RootInstanceProfile": { + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RootRole" + } + ] + }, + "Type": "AWS::IAM::InstanceProfile" + }, + "RootRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Path": "/", + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "root" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/websocket_api_with_none_auth.json b/tests/translator/output/websocket_api_with_none_auth.json new file mode 100644 index 0000000000..bae37df692 --- /dev/null +++ b/tests/translator/output/websocket_api_with_none_auth.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "ConnectFunction": { + "Properties": { + "Code": { + "ZipFile": "# placeholder" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ConnectFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "ConnectFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiConnectIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiConnectPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ConnectFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/default/$connect" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiConnectRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AuthorizationType": "NONE", + "RouteKey": "$connect", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiConnectIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiDefaultStage": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "StageName": "default", + "Tags": { + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/websocket_api_with_propagate_tags.json b/tests/translator/output/websocket_api_with_propagate_tags.json new file mode 100644 index 0000000000..2371764ee9 --- /dev/null +++ b/tests/translator/output/websocket_api_with_propagate_tags.json @@ -0,0 +1,216 @@ +{ + "Resources": { + "ApiGatewayDomainNameV25fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "DomainNameConfigurations": [ + { + "CertificateArn": "arn::cert::abc", + "EndpointType": "REGIONAL" + } + ], + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::DomainName" + }, + "DefaultFunction": { + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Handler": "bar", + "Role": { + "Fn::GetAtt": [ + "DefaultFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "DefaultFunctionRole": { + "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" + }, + "MyApi": { + "Properties": { + "Name": "MyApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action", + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiMapping": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "DomainName": { + "Ref": "ApiGatewayDomainNameV25fe29fe649" + }, + "Stage": { + "Ref": "MyApiProdStage" + } + }, + "Type": "AWS::ApiGatewayV2::ApiMapping" + }, + "MyApiDefaultIntegration": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::Sub": [ + "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations", + { + "FunctionArn": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + } + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Integration" + }, + "MyApiDefaultPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultFunction", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApi.ApiId}/Prod/$default" + } + }, + "Type": "AWS::Lambda::Permission" + }, + "MyApiDefaultRoute": { + "Properties": { + "ApiId": { + "Ref": "MyApi" + }, + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "MyApiDefaultIntegration" + } + ] + ] + } + }, + "Type": "AWS::ApiGatewayV2::Route" + }, + "MyApiProdStage": { + "DependsOn": [ + "MyApiDefaultRoute" + ], + "Properties": { + "AccessLogSettings": { + "DestinationArn": "random-arn", + "Format": "$context.requestId" + }, + "ApiId": { + "Ref": "MyApi" + }, + "AutoDeploy": true, + "RouteSettings": { + "$default": { + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 200, + "ThrottlingRateLimit": 0.7 + } + }, + "StageName": "Prod", + "StageVariables": { + "VarName": "VarValue" + }, + "Tags": { + "TagKey1": "Value1", + "TagKey2": "Value2", + "websocketapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNameV25fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +}