Skip to content

Commit

Permalink
feat: Added linking Gateway Method to Lambda Authorizer (aws#5228)
Browse files Browse the repository at this point in the history
* Added linking method to authorizer

* Fixed docstring spelling mistake

---------

Co-authored-by: Mohamed Elasmar <[email protected]>
  • Loading branch information
lucashuy and moelasmar committed Jun 22, 2023
1 parent 62a708d commit 664615b
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
14 changes: 14 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,20 @@ class GatewayAuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException(
"""


class OneGatewayMethodToGatewayAuthorizerLinkingLimitationException(OneResourceLinkingLimitationException):
"""
Exception specific for Gateway Method linking to more than one Gateway Authorizer
"""


class GatewayMethodToGatewayAuthorizerLocalVariablesLinkingLimitationException(
LocalVariablesLinkingLimitationException
):
"""
Exception specific for Gateway Method linking to Gateway Authorizer using locals.
"""


class InvalidSamMetadataPropertiesException(UserException):
pass

Expand Down
69 changes: 69 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/resource_linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from samcli.hook_packages.terraform.hooks.prepare.exceptions import (
FunctionLayerLocalVariablesLinkingLimitationException,
GatewayAuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayMethodToGatewayAuthorizerLocalVariablesLinkingLimitationException,
GatewayResourceToApiGatewayIntegrationLocalVariablesLinkingLimitationException,
GatewayResourceToApiGatewayIntegrationResponseLocalVariablesLinkingLimitationException,
GatewayResourceToApiGatewayMethodLocalVariablesLinkingLimitationException,
Expand All @@ -18,6 +19,7 @@
LambdaFunctionToApiGatewayIntegrationLocalVariablesLinkingLimitationException,
LocalVariablesLinkingLimitationException,
OneGatewayAuthorizerToLambdaFunctionLinkingLimitationException,
OneGatewayMethodToGatewayAuthorizerLinkingLimitationException,
OneGatewayResourceToApiGatewayIntegrationLinkingLimitationException,
OneGatewayResourceToApiGatewayIntegrationResponseLinkingLimitationException,
OneGatewayResourceToApiGatewayMethodLinkingLimitationException,
Expand Down Expand Up @@ -50,6 +52,7 @@
LAMBDA_LAYER_RESOURCE_ADDRESS_PREFIX = "aws_lambda_layer_version."
API_GATEWAY_REST_API_RESOURCE_ADDRESS_PREFIX = "aws_api_gateway_rest_api."
API_GATEWAY_RESOURCE_RESOURCE_ADDRESS_PREFIX = "aws_api_gateway_resource."
API_GATEWAY_AUTHORIZER_RESOURCE_ADDRESS_PREFIX = "aws_api_gateway_authorizer."
TERRAFORM_LOCAL_VARIABLES_ADDRESS_PREFIX = "local."
DATA_RESOURCE_ADDRESS_PREFIX = "data."

Expand Down Expand Up @@ -1566,3 +1569,69 @@ def _link_gateway_authorizer_to_lambda_function(
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_method_to_gateway_authorizer_call_back(
gateway_method_cfn_resource: Dict, authorizer_resources: List[ReferenceType]
) -> None:
"""
Callback function that is used by the linking algorithm to update a CFN Method Resource with
a reference to the Lambda Authorizers's Id
Parameters
----------
gateway_method_cfn_resource: Dict
API Gateway Method CFN resource
authorizer_resources: List[ReferenceType]
List of referenced Authorizers either as the logical id of Authorizer resources
defined in the customer project, or ARN values for actual Authorizers defined
in customer's account. This list should always contain one element only.
"""
if len(authorizer_resources) > 1:
raise InvalidResourceLinkingException("Could not link multiple Lambda Authorizers to one Gateway Method")

if not authorizer_resources:
LOG.info("Unable to find any references to Authorizers, skip linking Gateway Method to Lambda Authorizer")
return

logical_id = authorizer_resources[0]
gateway_method_cfn_resource["Properties"]["AuthorizerId"] = (
{"Ref": logical_id.value} if isinstance(logical_id, LogicalIdReference) else logical_id.value
)


def _link_gateway_method_to_gateway_authorizer(
gateway_method_config_resources: Dict[str, TFResource],
gateway_method_config_address_cfn_resources_map: Dict[str, List],
authorizer_resources: Dict[str, Dict],
) -> None:
"""
Iterate through all the resources and link the corresponding
Gateway Method resources to each Gateway Authorizer
Parameters
----------
gateway_method_config_resources: Dict[str, TFResource]
Dictionary of configuration Gateway Methods
gateway_method_config_address_cfn_resources_map: Dict[str, List]
Dictionary containing resolved configuration addresses matched up to the cfn Gateway Stage
authorizer_resources: Dict[str, Dict]
Dictionary of all Terraform Authorizer resources (not configuration resources).
The dictionary's key is the calculated logical id for each resource.
"""
exceptions = ResourcePairExceptions(
multiple_resource_linking_exception=OneGatewayMethodToGatewayAuthorizerLinkingLimitationException,
local_variable_linking_exception=GatewayMethodToGatewayAuthorizerLocalVariablesLinkingLimitationException,
)
resource_linking_pair = ResourceLinkingPair(
source_resource_cfn_resource=gateway_method_config_address_cfn_resources_map,
source_resource_tf_config=gateway_method_config_resources,
destination_resource_tf=authorizer_resources,
tf_destination_attribute_name="id",
terraform_link_field_name="authorizer_id",
cfn_link_field_name="AuthorizerId",
terraform_resource_type_prefix=API_GATEWAY_AUTHORIZER_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=_link_gateway_method_to_gateway_authorizer_call_back,
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
_link_gateway_integrations_to_function_resource,
_link_gateway_integrations_to_gateway_resource,
_link_gateway_integrations_to_gateway_rest_apis,
_link_gateway_method_to_gateway_authorizer,
_link_gateway_method_to_gateway_resource,
_link_gateway_methods_to_gateway_rest_apis,
_link_gateway_resources_to_gateway_rest_apis,
Expand Down Expand Up @@ -78,4 +79,9 @@
dest=TF_AWS_LAMBDA_FUNCTION,
linking_func=_link_gateway_authorizer_to_lambda_function,
),
LinkingPairCaller(
source=TF_AWS_API_GATEWAY_METHOD,
dest=TF_AWS_API_GATEWAY_AUTHORIZER,
linking_func=_link_gateway_method_to_gateway_authorizer,
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
from parameterized import parameterized
from samcli.hook_packages.terraform.hooks.prepare.exceptions import (
GatewayAuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayMethodToGatewayAuthorizerLocalVariablesLinkingLimitationException,
InvalidResourceLinkingException,
LocalVariablesLinkingLimitationException,
ONE_LAMBDA_LAYER_LINKING_ISSUE_LINK,
LOCAL_VARIABLES_SUPPORT_ISSUE_LINK,
APPLY_WORK_AROUND_MESSAGE,
OneGatewayAuthorizerToLambdaFunctionLinkingLimitationException,
OneGatewayMethodToGatewayAuthorizerLinkingLimitationException,
OneLambdaLayerLinkingLimitationException,
FunctionLayerLocalVariablesLinkingLimitationException,
OneGatewayResourceToApiGatewayMethodLinkingLimitationException,
Expand All @@ -36,9 +38,12 @@
)

from samcli.hook_packages.terraform.hooks.prepare.resource_linking import (
API_GATEWAY_AUTHORIZER_RESOURCE_ADDRESS_PREFIX,
_clean_references_list,
_link_gateway_authorizer_to_lambda_function,
_link_gateway_authorizer_to_lambda_function_call_back,
_link_gateway_method_to_gateway_authorizer,
_link_gateway_method_to_gateway_authorizer_call_back,
_resolve_module_output,
_resolve_module_variable,
_build_module,
Expand Down Expand Up @@ -2081,6 +2086,10 @@ def test_link_gateway_integration_to_function_call_back(
_link_gateway_resource_to_gateway_rest_apis_rest_api_id_call_back,
"Could not link multiple Rest APIs to one Gateway resource",
),
(
_link_gateway_method_to_gateway_authorizer_call_back,
"Could not link multiple Lambda Authorizers to one Gateway Method",
),
]
)
def test_linking_callbacks_raises_multiple_reference_exception(self, linking_call_back_method, expected_message):
Expand All @@ -2094,6 +2103,7 @@ def test_linking_callbacks_raises_multiple_reference_exception(self, linking_cal
(_link_gateway_resource_to_gateway_rest_apis_parent_id_call_back,),
(_link_gateway_resource_to_gateway_resource_call_back,),
(_link_gateway_resource_to_gateway_rest_apis_rest_api_id_call_back,),
(_link_gateway_method_to_gateway_authorizer_call_back,),
]
)
def test_linking_callbacks_skips_empty_references(self, linking_call_back_method):
Expand Down Expand Up @@ -2245,3 +2255,67 @@ def test_link_gateway_authorizer_to_lambda_function(
)

mock_resource_linker.assert_called_once_with(mock_resource_linking_pair())

@parameterized.expand(
[
(
[LogicalIdReference("Authorizer")],
{"Ref": "Authorizer"},
),
(
[ExistingResourceReference("Existing123")],
"Existing123",
),
]
)
def test_link_gateway_method_to_gateway_authorizer_call_back(self, logical_ids, expected_reference):
original_method = {
"Type": "AWS::ApiGateway::Method",
"Properties": {"AuthorizerId": "id here"},
}
new_method = deepcopy(original_method)

_link_gateway_method_to_gateway_authorizer_call_back(new_method, logical_ids)

original_method["Properties"]["AuthorizerId"] = expected_reference
self.assertEqual(original_method, new_method)

@patch(
"samcli.hook_packages.terraform.hooks.prepare.resource_linking._link_gateway_method_to_gateway_authorizer_call_back"
)
@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking.ResourceLinker")
@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking.ResourceLinkingPair")
@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking.ResourcePairExceptions")
def test_link_gateway_method_to_gateway_authorizer(
self,
mock_resource_linking_exceptions,
mock_resource_linking_pair,
mock_resource_linker,
mock_link_gateway_method_to_gateway_authorizer_call_back,
):
method_cfn_resources = Mock()
method_config_resources = Mock()
authorizer_tf_resources = Mock()

_link_gateway_method_to_gateway_authorizer(
method_config_resources, method_cfn_resources, authorizer_tf_resources
)

mock_resource_linking_exceptions.assert_called_once_with(
multiple_resource_linking_exception=OneGatewayMethodToGatewayAuthorizerLinkingLimitationException,
local_variable_linking_exception=GatewayMethodToGatewayAuthorizerLocalVariablesLinkingLimitationException,
)

mock_resource_linking_pair.assert_called_once_with(
source_resource_cfn_resource=method_cfn_resources,
source_resource_tf_config=method_config_resources,
destination_resource_tf=authorizer_tf_resources,
tf_destination_attribute_name="id",
terraform_link_field_name="authorizer_id",
cfn_link_field_name="AuthorizerId",
terraform_resource_type_prefix=API_GATEWAY_AUTHORIZER_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=mock_link_gateway_method_to_gateway_authorizer_call_back,
linking_exceptions=mock_resource_linking_exceptions(),
)

mock_resource_linker.assert_called_once_with(mock_resource_linking_pair())

0 comments on commit 664615b

Please sign in to comment.