|
10 | 10 | ApiGatewayApiKey,
|
11 | 11 | ApiGatewayAuthorizer,
|
12 | 12 | ApiGatewayBasePathMapping,
|
| 13 | + ApiGatewayBasePathMappingV2, |
13 | 14 | ApiGatewayDeployment,
|
14 | 15 | ApiGatewayDomainName,
|
| 16 | + ApiGatewayDomainNameV2, |
15 | 17 | ApiGatewayResponse,
|
16 | 18 | ApiGatewayRestApi,
|
17 | 19 | ApiGatewayStage,
|
@@ -78,7 +80,11 @@ class ApiDomainResponse:
|
78 | 80 | apigw_basepath_mapping_list: Optional[List[ApiGatewayBasePathMapping]]
|
79 | 81 | recordset_group: Any
|
80 | 82 |
|
81 |
| - |
| 83 | +@dataclass |
| 84 | +class ApiDomainResponseV2: |
| 85 | + domain: Optional[ApiGatewayDomainNameV2] |
| 86 | + apigw_basepath_mapping_list: Optional[List[ApiGatewayBasePathMappingV2]] |
| 87 | + recordset_group: Any |
82 | 88 | class SharedApiUsagePlan:
|
83 | 89 | """
|
84 | 90 | Collects API information from different API resources in the same template,
|
@@ -603,6 +609,129 @@ def _construct_api_domain( # noqa: PLR0912, PLR0915
|
603 | 609 |
|
604 | 610 | return ApiDomainResponse(domain, basepath_resource_list, record_set_group)
|
605 | 611 |
|
| 612 | + def _construct_api_domain_v2( |
| 613 | + self, rest_api: ApiGatewayRestApi, route53_record_set_groups: Any |
| 614 | + ) -> ApiDomainResponseV2: |
| 615 | + """ |
| 616 | + Constructs and returns the ApiGateway Domain and BasepathMapping |
| 617 | + """ |
| 618 | + if self.domain is None: |
| 619 | + return ApiDomainResponseV2(None, None, None) |
| 620 | + |
| 621 | + sam_expect(self.domain, self.logical_id, "Domain").to_be_a_map() |
| 622 | + domain_name: PassThrough = sam_expect( |
| 623 | + self.domain.get("DomainName"), self.logical_id, "Domain.DomainName" |
| 624 | + ).to_not_be_none() |
| 625 | + domain_name_arn: PassThrough = sam_expect( |
| 626 | + self.domain.get("DomainNameArn"), self.logical_id, "Domain.DomainNameArn" |
| 627 | + ) |
| 628 | + certificate_arn: PassThrough = sam_expect( |
| 629 | + self.domain.get("CertificateArn"), self.logical_id, "Domain.CertificateArn" |
| 630 | + ).to_not_be_none() |
| 631 | + |
| 632 | + api_domain_name = "{}{}".format("ApiGatewayDomainNameV2", LogicalIdGenerator("", domain_name).gen()) |
| 633 | + self.domain["ApiDomainName"] = api_domain_name |
| 634 | + domain = ApiGatewayDomainNameV2(api_domain_name, attributes=self.passthrough_resource_attributes) |
| 635 | + |
| 636 | + domain.DomainName = domain_name |
| 637 | + endpoint = self.domain.get("EndpointConfiguration") |
| 638 | + |
| 639 | + if endpoint not in ["EDGE", "REGIONAL", "PRIVATE"]: |
| 640 | + raise InvalidResourceException( |
| 641 | + self.logical_id, |
| 642 | + "EndpointConfiguration for Custom Domains must be" |
| 643 | + " one of {}.".format(["EDGE", "REGIONAL", "PRIVATE"]), |
| 644 | + ) |
| 645 | + |
| 646 | + domain.CertificateArn = certificate_arn |
| 647 | + |
| 648 | + domain.EndpointConfiguration = {"Types": [endpoint]} |
| 649 | + |
| 650 | + if self.domain.get("SecurityPolicy", None): |
| 651 | + domain.SecurityPolicy = self.domain["SecurityPolicy"] |
| 652 | + |
| 653 | + if self.domain.get("Policy", None): |
| 654 | + domain.Policy = self.domain["Policy"] |
| 655 | + |
| 656 | + basepaths: Optional[List[str]] |
| 657 | + basepath_value = self.domain.get("BasePath") |
| 658 | + # Create BasepathMappings |
| 659 | + if self.domain.get("BasePath") and isinstance(basepath_value, str): |
| 660 | + basepaths = [basepath_value] |
| 661 | + elif self.domain.get("BasePath") and isinstance(basepath_value, list): |
| 662 | + basepaths = cast(Optional[List[Any]], basepath_value) |
| 663 | + else: |
| 664 | + basepaths = None |
| 665 | + |
| 666 | + # Boolean to allow/disallow symbols in BasePath property |
| 667 | + normalize_basepath = self.domain.get("NormalizeBasePath", True) |
| 668 | + |
| 669 | + basepath_resource_list: List[ApiGatewayBasePathMappingV2] = [] |
| 670 | + if basepaths is None: |
| 671 | + basepath_mapping = ApiGatewayBasePathMappingV2( |
| 672 | + self.logical_id + "BasePathMapping", attributes=self.passthrough_resource_attributes |
| 673 | + ) |
| 674 | + basepath_mapping.DomainNameArn = ref(domain_name_arn) |
| 675 | + basepath_mapping.RestApiId = ref(rest_api.logical_id) |
| 676 | + basepath_mapping.Stage = ref(rest_api.logical_id + ".Stage") |
| 677 | + basepath_resource_list.extend([basepath_mapping]) |
| 678 | + else: |
| 679 | + sam_expect(basepaths, self.logical_id, "Domain.BasePath").to_be_a_list_of(ExpectedType.STRING) |
| 680 | + for basepath in basepaths: |
| 681 | + # Remove possible leading and trailing '/' because a base path may only |
| 682 | + # contain letters, numbers, and one of "$-_.+!*'()" |
| 683 | + path = "".join(e for e in basepath if e.isalnum()) |
| 684 | + logical_id = "{}{}{}".format(self.logical_id, path, "BasePathMapping") |
| 685 | + basepath_mapping = ApiGatewayBasePathMappingV2( |
| 686 | + logical_id, attributes=self.passthrough_resource_attributes |
| 687 | + ) |
| 688 | + basepath_mapping.DomainNameArn = ref(domain_name_arn) |
| 689 | + basepath_mapping.RestApiId = ref(rest_api.logical_id) |
| 690 | + basepath_mapping.Stage = ref(rest_api.logical_id + ".Stage") |
| 691 | + basepath_mapping.BasePath = path if normalize_basepath else basepath |
| 692 | + basepath_resource_list.extend([basepath_mapping]) |
| 693 | + |
| 694 | + # Create the Route53 RecordSetGroup resource |
| 695 | + record_set_group = None |
| 696 | + route53 = self.domain.get("Route53") |
| 697 | + if route53 is not None: |
| 698 | + sam_expect(route53, self.logical_id, "Domain.Route53").to_be_a_map() |
| 699 | + if route53.get("HostedZoneId") is None and route53.get("HostedZoneName") is None: |
| 700 | + raise InvalidResourceException( |
| 701 | + self.logical_id, |
| 702 | + "HostedZoneId or HostedZoneName is required to enable Route53 support on Custom Domains.", |
| 703 | + ) |
| 704 | + |
| 705 | + logical_id_suffix = LogicalIdGenerator( |
| 706 | + "", route53.get("HostedZoneId") or route53.get("HostedZoneName") |
| 707 | + ).gen() |
| 708 | + logical_id = "RecordSetGroup" + logical_id_suffix |
| 709 | + |
| 710 | + record_set_group = route53_record_set_groups.get(logical_id) |
| 711 | + |
| 712 | + if route53.get("SeparateRecordSetGroup"): |
| 713 | + sam_expect( |
| 714 | + route53.get("SeparateRecordSetGroup"), self.logical_id, "Domain.Route53.SeparateRecordSetGroup" |
| 715 | + ).to_be_a_bool() |
| 716 | + return ApiDomainResponseV2( |
| 717 | + domain, |
| 718 | + basepath_resource_list, |
| 719 | + self._construct_single_record_set_group(self.domain, domain_name, route53), |
| 720 | + ) |
| 721 | + |
| 722 | + if not record_set_group: |
| 723 | + record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) |
| 724 | + if "HostedZoneId" in route53: |
| 725 | + record_set_group.HostedZoneId = route53.get("HostedZoneId") |
| 726 | + if "HostedZoneName" in route53: |
| 727 | + record_set_group.HostedZoneName = route53.get("HostedZoneName") |
| 728 | + record_set_group.RecordSets = [] |
| 729 | + route53_record_set_groups[logical_id] = record_set_group |
| 730 | + |
| 731 | + record_set_group.RecordSets += self._construct_record_sets_for_domain(self.domain, domain_name, route53) |
| 732 | + |
| 733 | + return ApiDomainResponseV2(domain, basepath_resource_list, record_set_group) |
| 734 | + |
606 | 735 | def _construct_single_record_set_group(
|
607 | 736 | self, domain: Dict[str, Any], api_domain_name: str, route53: Any
|
608 | 737 | ) -> Route53RecordSetGroup:
|
@@ -677,9 +806,15 @@ def to_cloudformation(
|
677 | 806 | :rtype: tuple
|
678 | 807 | """
|
679 | 808 | rest_api = self._construct_rest_api()
|
680 |
| - api_domain_response = self._construct_api_domain(rest_api, route53_record_set_groups) |
681 |
| - domain = api_domain_response.domain |
682 |
| - basepath_mapping = api_domain_response.apigw_basepath_mapping_list |
| 809 | + if self.endpoint_configuration == "PRIVATE": |
| 810 | + api_domain_response = self._construct_api_domain_v2(rest_api, route53_record_set_groups) |
| 811 | + domain = api_domain_response.domain |
| 812 | + basepath_mapping = api_domain_response.apigw_basepath_mapping_list |
| 813 | + else: |
| 814 | + api_domain_response = self._construct_api_domain(rest_api, route53_record_set_groups) |
| 815 | + domain = api_domain_response.domain |
| 816 | + basepath_mapping = api_domain_response.apigw_basepath_mapping_list |
| 817 | + |
683 | 818 | route53_recordsetGroup = api_domain_response.recordset_group
|
684 | 819 |
|
685 | 820 | deployment = self._construct_deployment(rest_api)
|
|
0 commit comments