From 5ef82f64dfcc8e4ae32b281ffec59fd0622a6d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morosi?= Date: Fri, 12 Jan 2024 09:32:41 +0100 Subject: [PATCH] Fix RestApi referencing $default in LambdaPermission Apigateway v1 doesn't allow $ in the stage name and so it was removed when declaring the stage, while still used in the LambdaPermission. Also remove the special case that prevented having Default in the name of some resources --- src/e3/aws/troposphere/apigateway/__init__.py | 27 +++++++++---------- .../troposphere/apigateway/apigateway_test.py | 6 ++--- .../apigateway/apigatewayv1_test.json | 8 +++--- .../apigatewayv1_test_custom_domain.json | 10 +++---- ...pigatewayv1_test_custom_domain_stages.json | 10 +++---- .../apigatewayv1_test_lambda_alias.json | 8 +++--- .../apigatewayv1_test_nested_resources.json | 16 +++++------ .../apigateway/apigatewayv1_test_stages.json | 8 +++--- 8 files changed, 45 insertions(+), 48 deletions(-) diff --git a/src/e3/aws/troposphere/apigateway/__init__.py b/src/e3/aws/troposphere/apigateway/__init__.py index af0b9e9..1bb77db 100644 --- a/src/e3/aws/troposphere/apigateway/__init__.py +++ b/src/e3/aws/troposphere/apigateway/__init__.py @@ -23,7 +23,6 @@ from troposphere import AWSObject from troposphere.certificatemanager import Certificate, DomainValidationOption import json -import re if TYPE_CHECKING: from e3.aws.troposphere import Stack @@ -195,6 +194,9 @@ class _AliasTargetAttributes(TypedDict): DNSName: str HostedZoneId: str + # The default stage name + DEFAULT_STAGE_NAME = "$default" + def __init__( self, name: str, @@ -240,7 +242,9 @@ def __init__( self.authorizers: dict[str, Any] = {} # By default, make sure to have a $default stage self.stages_config = ( - stages_config if stages_config else [StageConfiguration("$default")] + stages_config + if stages_config + else [StageConfiguration(self.DEFAULT_STAGE_NAME)] ) @cached_property @@ -697,6 +701,9 @@ def resources(self, stack: Stack) -> list[AWSObject]: class RestApi(Api): """Rest API support.""" + # Apigateway v1 only allows a-zA-Z0-9_ + DEFAULT_STAGE_NAME = "default" + def __init__( self, name: str, @@ -878,8 +885,7 @@ def declare_stage( DeploymentId=Ref(deployment_name), Description=f"stage {stage_name}", MethodSettings=[method_settings], - # Stage name only allows a-zA-Z0-9_ - StageName=re.sub("[^a-zA-Z0-9_]", "", stage_name), + StageName=stage_name, **parameters, ) ) @@ -948,12 +954,7 @@ def _declare_method( for config in self.stages_config: result.append( awslambda.Permission( - # Retain old behavior for the $default stage - name_to_id( - "{}-{}LambdaPermission".format( - id_prefix, "" if config.name == "$default" else config.name - ) - ), + name_to_id(f"{id_prefix}-{config.name}LambdaPermission"), Action="lambda:InvokeFunction", FunctionName=lambda_arn, Principal="apigateway.amazonaws.com", @@ -1006,11 +1007,7 @@ def _declare_api_mapping( apigateway.BasePathMapping( # Retain old behavior for the $default stage name_to_id( - "{}{}-{}BasePathMapping".format( - self.name, - domain_name.DomainName, - "" if config.name == "$default" else config.name, - ) + f"{self.name}{domain_name.DomainName}-{config.name}BasePathMapping" ), **mapping_params, ) diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigateway_test.py b/tests/tests_e3_aws/troposphere/apigateway/apigateway_test.py index 2584e56..5a94dbe 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigateway_test.py +++ b/tests/tests_e3_aws/troposphere/apigateway/apigateway_test.py @@ -529,7 +529,7 @@ def test_rest_api_stages(stack: Stack, lambda_fun: PyFunction) -> None: Method("ANY"), ], stages_config=[ - StageConfiguration("$default"), + StageConfiguration("default"), StageConfiguration( "beta", api_mapping_key="beta", variables={"somevar": "somevalue"} ), @@ -574,7 +574,7 @@ def test_rest_api_lambda_alias(stack: Stack, lambda_fun: PyFunction) -> None: ], stages_config=[ StageConfiguration( - "$default", + "default", lambda_arn_permission=lambda_aliases.blue.ref, variables={"lambdaAlias": lambda_aliases.blue.name}, ), @@ -667,7 +667,7 @@ def test_rest_api_custom_domain_stages(stack: Stack, lambda_fun: PyFunction) -> Method("ANY", authorizer_name="testauthorizer"), ], stages_config=[ - StageConfiguration("$default"), + StageConfiguration("default"), StageConfiguration( "beta", api_mapping_key="beta", variables={"somevar": "somevalue"} ), diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test.json index 0926f11..16abfb8 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test.json @@ -45,7 +45,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -72,7 +72,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -116,7 +116,7 @@ }, "Type": "AWS::ApiGateway::Method" }, - "TestapiANYLambdaPermission": { + "TestapiANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -125,7 +125,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/*", { "api": { "Ref": "Testapi" diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain.json index 5d4cf0f..4a4c7a2 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain.json @@ -71,7 +71,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -98,7 +98,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -145,7 +145,7 @@ }, "Type": "AWS::ApiGateway::Method" }, - "TestapiANYLambdaPermission": { + "TestapiANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -154,7 +154,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/*", { "api": { "Ref": "Testapi" @@ -188,7 +188,7 @@ }, "Type": "AWS::ApiGateway::DomainName" }, - "TestapiapiexamplecomBasePathMapping": { + "TestapiapiexamplecomDefaultBasePathMapping": { "Properties": { "DomainName": { "Ref": "TestapiapiexamplecomDomain" diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain_stages.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain_stages.json index 3e6bba8..a09c883 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain_stages.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_custom_domain_stages.json @@ -71,7 +71,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -98,7 +98,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -212,7 +212,7 @@ }, "Type": "AWS::Lambda::Permission" }, - "TestapiANYLambdaPermission": { + "TestapiANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -221,7 +221,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/*", { "api": { "Ref": "Testapi" @@ -255,7 +255,7 @@ }, "Type": "AWS::ApiGateway::DomainName" }, - "TestapiapiexamplecomBasePathMapping": { + "TestapiapiexamplecomDefaultBasePathMapping": { "Properties": { "DomainName": { "Ref": "TestapiapiexamplecomDomain" diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_lambda_alias.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_lambda_alias.json index 3bb7d4f..ac18d39 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_lambda_alias.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_lambda_alias.json @@ -91,7 +91,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -118,7 +118,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -177,7 +177,7 @@ }, "Type": "AWS::Lambda::Permission" }, - "TestapiANYLambdaPermission": { + "TestapiANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -186,7 +186,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/*", { "api": { "Ref": "Testapi" diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_nested_resources.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_nested_resources.json index 00efe7d..99b437d 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_nested_resources.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_nested_resources.json @@ -75,7 +75,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -104,7 +104,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -208,7 +208,7 @@ }, "Type": "AWS::ApiGateway::Method" }, - "TestapiAccountsANYLambdaPermission": { + "TestapiAccountsANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -217,7 +217,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/accounts", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/accounts", { "api": { "Ref": "Testapi" @@ -229,7 +229,7 @@ }, "Type": "AWS::Lambda::Permission" }, - "TestapiProductsANYLambdaPermission": { + "TestapiProductsANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -238,7 +238,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/products", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/products", { "api": { "Ref": "Testapi" @@ -250,7 +250,7 @@ }, "Type": "AWS::Lambda::Permission" }, - "TestapiProductsAbcdANYLambdaPermission": { + "TestapiProductsAbcdANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -259,7 +259,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/products/abcd", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/products/abcd", { "api": { "Ref": "Testapi" diff --git a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_stages.json b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_stages.json index ea08f6d..1335b15 100644 --- a/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_stages.json +++ b/tests/tests_e3_aws/troposphere/apigateway/apigatewayv1_test_stages.json @@ -91,7 +91,7 @@ }, "TestapiDefaultDeployment": { "Properties": { - "Description": "Deployment resource of $default stage", + "Description": "Deployment resource of default stage", "RestApiId": { "Ref": "Testapi" } @@ -118,7 +118,7 @@ "DeploymentId": { "Ref": "TestapiDefaultDeployment" }, - "Description": "stage $default", + "Description": "stage default", "MethodSettings": [ { "ResourcePath": "/*", @@ -183,7 +183,7 @@ }, "Type": "AWS::Lambda::Permission" }, - "TestapiANYLambdaPermission": { + "TestapiANYDefaultLambdaPermission": { "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { @@ -192,7 +192,7 @@ "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/$default/${method}/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/default/${method}/*", { "api": { "Ref": "Testapi"