Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Link V2 Route to V2 API #5503

Merged
merged 9 commits into from
Jul 14, 2023
12 changes: 12 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,18 @@ class GatewayV2IntegrationToGatewayV2ApiLocalVariablesLinkingLimitationException
"""


class OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException(OneResourceLinkingLimitationException):
"""
Exception specific for Gateway V2 Route linking to more than one Gateway V2 API
"""


class GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException(LocalVariablesLinkingLimitationException):
"""
Exception specific for Gateway V2 Route linking to Gateway V2 API using locals.
"""


class InvalidSamMetadataPropertiesException(UserException):
pass

Expand Down
53 changes: 46 additions & 7 deletions samcli/hook_packages/terraform/hooks/prepare/resource_linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
GatewayResourceToGatewayRestApiLocalVariablesLinkingLimitationException,
GatewayV2IntegrationToGatewayV2ApiLocalVariablesLinkingLimitationException,
GatewayV2IntegrationToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException,
GatewayV2RouteToGatewayV2IntegrationLocalVariablesLinkingLimitationException,
InvalidResourceLinkingException,
LambdaFunctionToApiGatewayIntegrationLocalVariablesLinkingLimitationException,
Expand All @@ -31,6 +32,7 @@
OneGatewayResourceToRestApiLinkingLimitationException,
OneGatewayV2IntegrationToGatewayV2ApiLinkingLimitationException,
OneGatewayV2IntegrationToLambdaFunctionLinkingLimitationException,
OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException,
OneGatewayV2RouteToGatewayV2IntegrationLinkingLimitationException,
OneLambdaFunctionResourceToApiGatewayIntegrationLinkingLimitationException,
OneLambdaLayerLinkingLimitationException,
Expand Down Expand Up @@ -1897,33 +1899,33 @@ def _link_gateway_v2_integration_to_lambda_function(
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_v2_integration_to_api_callback(
gateway_v2_integration_cfn_resource: Dict, gateway_v2_api_resources: List[ReferenceType]
def _link_gateway_v2_resource_to_api_callback(
gateway_v2_resource_cfn_resource: Dict, gateway_v2_api_resources: List[ReferenceType]
):
"""
Callback function that is used by the linking algorithm to update a CFN V2 Integration Resource with
a reference to the Gateway V2 Api resource

Parameters
----------
gateway_v2_integration_cfn_resource: Dict
gateway_v2_resource_cfn_resource: Dict
API Gateway V2 Integration CFN resource
gateway_v2_api_resources: List[ReferenceType]
List of referenced Gateway V2 Apis either as the logical id of Apis resources
defined in the customer project, or ARN values for actual Api defined
in customer's account. This list should always contain one element only.
"""
if len(gateway_v2_api_resources) > 1:
raise InvalidResourceLinkingException("Could not link multiple Gateway V2 Apis to one Gateway V2 Integration")
raise InvalidResourceLinkingException("Could not link multiple Gateway V2 Apis to one Gateway V2 resource")

if not gateway_v2_api_resources:
LOG.info(
"Unable to find any references to Gateway V2 APIs, skip linking Gateway V2 Integration to Gateway V2 APIs"
"Unable to find any references to Gateway V2 APIs, skip linking Gateway V2 resources to Gateway V2 APIs"
)
return

logical_id = gateway_v2_api_resources[0]
gateway_v2_integration_cfn_resource["Properties"]["ApiId"] = (
gateway_v2_resource_cfn_resource["Properties"]["ApiId"] = (
{"Ref": logical_id.value} if isinstance(logical_id, LogicalIdReference) else logical_id.value
)

Expand Down Expand Up @@ -1959,7 +1961,44 @@ def _link_gateway_v2_integration_to_api(
terraform_link_field_name="api_id",
cfn_link_field_name="ApiId",
terraform_resource_type_prefix=API_GATEWAY_V2_API_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=_link_gateway_v2_integration_to_api_callback,
cfn_resource_update_call_back_function=_link_gateway_v2_resource_to_api_callback,
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_v2_route_to_api(
gateway_route_config_resources: Dict[str, TFResource],
gateway_route_config_address_cfn_resources_map: Dict[str, List],
api_resources: Dict[str, Dict],
) -> None:
"""
Iterate through all the resources and link the corresponding
Gateway V2 Route resources to each Gateway V2 Api

Parameters
----------
gateway_route_config_resources: Dict[str, TFResource]
Dictionary of configuration Gateway Integrations
gateway_route_config_address_cfn_resources_map: Dict[str, List]
Dictionary containing resolved configuration addresses matched up to the cfn Gateway Route
api_resources: Dict[str, Dict]
Dictionary of all Terraform Gateway V2 Api resources (not configuration resources).
The dictionary's key is the calculated logical id for each resource.
"""
exceptions = ResourcePairExceptions(
multiple_resource_linking_exception=OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException,
local_variable_linking_exception=GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException,
)
resource_linking_pair = ResourceLinkingPair(
source_resource_cfn_resource=gateway_route_config_address_cfn_resources_map,
source_resource_tf_config=gateway_route_config_resources,
destination_resource_tf=api_resources,
tf_destination_attribute_name="id",
terraform_link_field_name="api_id",
cfn_link_field_name="ApiId",
terraform_resource_type_prefix=API_GATEWAY_V2_API_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=_link_gateway_v2_resource_to_api_callback,
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
_link_gateway_stage_to_rest_api,
_link_gateway_v2_integration_to_api,
_link_gateway_v2_integration_to_lambda_function,
_link_gateway_v2_route_to_api,
_link_gateway_v2_route_to_integration,
_link_lambda_functions_to_layers,
)
Expand Down Expand Up @@ -111,4 +112,9 @@
dest=TF_AWS_API_GATEWAY_V2_API,
linking_func=_link_gateway_v2_integration_to_api,
),
LinkingPairCaller(
source=TF_AWS_API_GATEWAY_V2_ROUTE,
dest=TF_AWS_API_GATEWAY_V2_API,
linking_func=_link_gateway_v2_route_to_api,
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
GatewayV2IntegrationToLambdaFunctionLocalVariablesLinkingLimitationException,
OneGatewayV2IntegrationToGatewayV2ApiLinkingLimitationException,
GatewayV2IntegrationToGatewayV2ApiLocalVariablesLinkingLimitationException,
OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException,
GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException,
)

from samcli.hook_packages.terraform.hooks.prepare.resource_linking import (
Expand Down Expand Up @@ -95,7 +97,8 @@
_extract_gateway_v2_integration_id_from_route_target_value,
_link_gateway_v2_integration_to_api,
API_GATEWAY_V2_API_RESOURCE_ADDRESS_PREFIX,
_link_gateway_v2_integration_to_api_callback,
_link_gateway_v2_resource_to_api_callback,
_link_gateway_v2_route_to_api,
)
from samcli.hook_packages.terraform.hooks.prepare.utilities import get_configuration_address
from samcli.hook_packages.terraform.hooks.prepare.types import (
Expand Down Expand Up @@ -2132,8 +2135,8 @@ def test_link_gateway_integration_to_function_call_back(
"Could not link multiple lambda functions to one Gateway V2 Integration",
),
(
_link_gateway_v2_integration_to_api_callback,
"Could not link multiple Gateway V2 Apis to one Gateway V2 Integration",
_link_gateway_v2_resource_to_api_callback,
"Could not link multiple Gateway V2 Apis to one Gateway V2 resource",
),
]
)
Expand All @@ -2151,7 +2154,7 @@ def test_linking_callbacks_raises_multiple_reference_exception(self, linking_cal
(_link_gateway_method_to_gateway_authorizer_call_back,),
(_link_gateway_v2_route_to_integration_callback,),
(_link_gateway_v2_integration_to_lambda_function_callback,),
(_link_gateway_v2_integration_to_api_callback,),
(_link_gateway_v2_resource_to_api_callback,),
]
)
def test_linking_callbacks_skips_empty_references(self, linking_call_back_method):
Expand Down Expand Up @@ -2584,7 +2587,7 @@ def test_extract_gateway_v2_integration_id_from_route_target_value(self, input_v
output = _extract_gateway_v2_integration_id_from_route_target_value(input_value)
self.assertEqual(output, expected_output)

@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._link_gateway_v2_integration_to_api_callback")
@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._link_gateway_v2_resource_to_api_callback")
@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")
Expand Down Expand Up @@ -2622,6 +2625,42 @@ def test_link_gateway_v2_integration_to_gateway_v2_api(

mock_resource_linker.assert_called_once_with(mock_resource_linking_pair())

@patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._link_gateway_v2_resource_to_api_callback")
@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_v2_route_to_gateway_v2_api(
self,
mock_resource_linking_exceptions,
mock_resource_linking_pair,
mock_resource_linker,
mock_link_gateway_v2_route_to_api_callback,
):
routes_v2_cfn_resources = Mock()
routes_v2_config_resources = Mock()
apis_v2_tf_resources = Mock()

_link_gateway_v2_route_to_api(routes_v2_config_resources, routes_v2_cfn_resources, apis_v2_tf_resources)

mock_resource_linking_exceptions.assert_called_once_with(
multiple_resource_linking_exception=OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException,
local_variable_linking_exception=GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException,
)

mock_resource_linking_pair.assert_called_once_with(
source_resource_cfn_resource=routes_v2_cfn_resources,
source_resource_tf_config=routes_v2_config_resources,
destination_resource_tf=apis_v2_tf_resources,
tf_destination_attribute_name="id",
terraform_link_field_name="api_id",
cfn_link_field_name="ApiId",
terraform_resource_type_prefix=API_GATEWAY_V2_API_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=mock_link_gateway_v2_route_to_api_callback,
linking_exceptions=mock_resource_linking_exceptions(),
)

mock_resource_linker.assert_called_once_with(mock_resource_linking_pair())

@parameterized.expand(
[
(
Expand All @@ -2646,6 +2685,6 @@ def test_link_gateway_v2_integration_to_api_callback(
self, input_gateway_v2_integration, logical_ids, expected_api_reference
):
gateway_resource = deepcopy(input_gateway_v2_integration)
_link_gateway_v2_integration_to_api_callback(gateway_resource, logical_ids)
_link_gateway_v2_resource_to_api_callback(gateway_resource, logical_ids)
input_gateway_v2_integration["Properties"]["ApiId"] = expected_api_reference
self.assertEqual(gateway_resource, input_gateway_v2_integration)