Skip to content

Commit 893aa90

Browse files
committed
feat: add support for IpAddressType
1 parent e5afb37 commit 893aa90

24 files changed

+2198
-275
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[
2+
{
3+
"LogicalResourceId": "MyApi",
4+
"ResourceType": "AWS::ApiGateway::RestApi"
5+
},
6+
{
7+
"LogicalResourceId": "MyApiDeployment",
8+
"ResourceType": "AWS::ApiGateway::Deployment"
9+
},
10+
{
11+
"LogicalResourceId": "MyApiProdStage",
12+
"ResourceType": "AWS::ApiGateway::Stage"
13+
},
14+
{
15+
"LogicalResourceId": "ApiGatewayDomainName",
16+
"ResourceType": "AWS::ApiGateway::DomainName"
17+
},
18+
{
19+
"LogicalResourceId": "MyApiBasePathMapping",
20+
"ResourceType": "AWS::ApiGateway::BasePathMapping"
21+
}
22+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"LogicalResourceId": "MyApi",
4+
"ResourceType": "AWS::ApiGateway::RestApi"
5+
},
6+
{
7+
"LogicalResourceId": "MyApiDeployment",
8+
"ResourceType": "AWS::ApiGateway::Deployment"
9+
},
10+
{
11+
"LogicalResourceId": "MyApiProdStage",
12+
"ResourceType": "AWS::ApiGateway::Stage"
13+
}
14+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Parameters:
2+
IpAddressType:
3+
Type: String
4+
Default: dualstack
5+
DomainName:
6+
Type: String
7+
CertificateArn:
8+
Type: String
9+
10+
Resources:
11+
MyApi:
12+
Type: AWS::Serverless::Api
13+
Properties:
14+
StageName: Prod
15+
DefinitionUri: ${definitionuri}
16+
Domain:
17+
DomainName: !Ref DomainName
18+
CertificateArn: !Ref CertificateArn
19+
EndpointConfiguration: REGIONAL
20+
IpAddressType: !Ref IpAddressType
21+
22+
Metadata:
23+
SamTransformTest: true
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Parameters:
2+
IpAddressType:
3+
Type: String
4+
Default: ipv4
5+
6+
Resources:
7+
MyApi:
8+
Type: AWS::Serverless::Api
9+
Properties:
10+
StageName: Prod
11+
DefinitionUri: ${definitionuri}
12+
EndpointConfiguration:
13+
Type: REGIONAL
14+
IpAddressType: !Ref IpAddressType
15+
Metadata:
16+
SamTransformTest: true
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from unittest.case import skipIf
2+
3+
from integration.config.service_names import REST_API
4+
from integration.helpers.base_internal_test import BaseInternalTest
5+
from integration.helpers.resource import current_region_does_not_support
6+
7+
8+
@skipIf(
9+
current_region_does_not_support([REST_API]),
10+
"Rest API is not supported in this testing region",
11+
)
12+
class TestApiWithDomainIpAddressType(BaseInternalTest):
13+
"""
14+
Test AWS::Serverless::Api with IpAddressType in Domain configuration
15+
"""
16+
17+
def test_api_with_domain_ipaddresstype(self):
18+
"""
19+
Creates an API with custom domain and IpAddressType set to dualstack
20+
"""
21+
self.create_and_verify_stack("single/api_with_domain_ipaddresstype")
22+
23+
# Verify the domain name resource
24+
domain_name_id = self.get_physical_id_by_type("AWS::ApiGateway::DomainName")
25+
api_gateway_client = self.client_provider.api_client
26+
result = api_gateway_client.get_domain_name(domainName=domain_name_id)
27+
28+
# Verify endpoint configuration
29+
end_point_config = result["endpointConfiguration"]
30+
end_point_types = end_point_config["types"]
31+
self.assertEqual(1, len(end_point_types))
32+
self.assertEqual("REGIONAL", end_point_types[0])
33+
34+
# Verify IpAddressType is set correctly
35+
self.assertEqual("dualstack", end_point_config["ipAddressType"])
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from unittest.case import skipIf
2+
3+
from integration.config.service_names import REST_API
4+
from integration.helpers.base_test import BaseTest
5+
from integration.helpers.resource import current_region_does_not_support
6+
7+
8+
@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
9+
class TestApiWithIpAddressType(BaseTest):
10+
"""
11+
Test AWS::Serverless::Api with IpAddressType in EndpointConfiguration
12+
"""
13+
14+
def test_api_with_ipaddresstype(self):
15+
"""
16+
Creates an API with IpAddressType set to ipv4
17+
"""
18+
parameters = [{"ParameterKey": "IpAddressType", "ParameterValue": "ipv4"}]
19+
self.create_and_verify_stack("single/api_with_ipaddresstype", parameters)
20+
21+
rest_api_id = self.get_physical_id_by_type("AWS::ApiGateway::RestApi")
22+
rest_api = self.client_provider.api_client.get_rest_api(restApiId=rest_api_id)
23+
24+
self.assertEqual(rest_api["endpointConfiguration"]["types"], ["REGIONAL"])
25+
self.assertEqual(rest_api["endpointConfiguration"]["ipAddressType"], "ipv4")

samtranslator/internal/schema_source/aws_serverless_api.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ class Domain(BaseModel):
175175
EndpointConfiguration: Optional[SamIntrinsicable[Literal["REGIONAL", "EDGE", "PRIVATE"]]] = domain(
176176
"EndpointConfiguration"
177177
)
178+
IpAddressType: Optional[PassThroughProp] = passthrough_prop(
179+
DOMAIN_STEM,
180+
"IpAddressType",
181+
["AWS::ApiGateway::DomainName.EndpointConfiguration", "IpAddressType"],
182+
)
178183
MutualTlsAuthentication: Optional[PassThroughProp] = passthrough_prop(
179184
DOMAIN_STEM,
180185
"MutualTlsAuthentication",
@@ -223,6 +228,11 @@ class EndpointConfiguration(BaseModel):
223228
"VPCEndpointIds",
224229
["AWS::ApiGateway::RestApi.EndpointConfiguration", "VpcEndpointIds"],
225230
)
231+
IpAddressType: Optional[PassThroughProp] = passthrough_prop(
232+
ENDPOINT_CONFIGURATION_STEM,
233+
"IpAddressType",
234+
["AWS::ApiGateway::RestApi.EndpointConfiguration", "IpAddressType"],
235+
)
226236

227237

228238
Name = Optional[PassThroughProp]

samtranslator/internal/schema_source/sam-docs.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@
4949
"NormalizeBasePath": "Indicates whether non\\-alphanumeric characters are allowed in basepaths defined by the `BasePath` property\\. When set to `True`, non\\-alphanumeric characters are removed from basepaths\\. \nUse `NormalizeBasePath` with the `BasePath` property\\. \n*Type*: Boolean \n*Required*: No \n*Default*: True \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
5050
"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-resource-apigateway-domainname.html#cfn-apigateway-domainname-ownershipverificationcertificatearn) property of an `AWS::ApiGateway::DomainName` resource\\.",
5151
"Route53": "Defines an Amazon Route\u00a053 configuration\\. \n*Type*: [Route53Configuration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-route53configuration.html) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
52-
"SecurityPolicy": "The TLS version plus cipher suite for this domain name\\. \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-resource-apigateway-domainname.html#cfn-apigateway-domainname-securitypolicy) property of an `AWS::ApiGateway::DomainName` resource\\."
52+
"SecurityPolicy": "The TLS version plus cipher suite for this domain name\\. \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-resource-apigateway-domainname.html#cfn-apigateway-domainname-securitypolicy) property of an `AWS::ApiGateway::DomainName` resource\\.",
53+
"IpAddressType": "The IP address types that can invoke this DomainName. Use `ipv4` to allow only IPv4 addresses to invoke this DomainName, or use `dualstack` to allow both IPv4 and IPv6 addresses to invoke this DomainName. For the `PRIVATE` endpoint type, only `dualstack` is supported. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`IpAddressType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-domainname-endpointconfiguration.html#cfn-apigateway-domainname-endpointconfiguration-ipaddresstype) property of an `AWS::ApiGateway::DomainName.EndpointConfiguration` resource."
5354
},
5455
"sam-property-api-endpointconfiguration": {
5556
"Type": "The endpoint type of a REST API\\. \n*Valid values*: `EDGE` or `REGIONAL` or `PRIVATE` \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`Types`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html#cfn-apigateway-restapi-endpointconfiguration-types) property of the `AWS::ApiGateway::RestApi` `EndpointConfiguration` data type\\.",
56-
"VPCEndpointIds": "A list of VPC endpoint IDs of a REST API against which to create Route53 aliases\\. \n*Type*: List \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcEndpointIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html#cfn-apigateway-restapi-endpointconfiguration-vpcendpointids) property of the `AWS::ApiGateway::RestApi` `EndpointConfiguration` data type\\."
57+
"VPCEndpointIds": "A list of VPC endpoint IDs of a REST API against which to create Route53 aliases\\. \n*Type*: List \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`VpcEndpointIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html#cfn-apigateway-restapi-endpointconfiguration-vpcendpointids) property of the `AWS::ApiGateway::RestApi` `EndpointConfiguration` data type\\.",
58+
"IpAddressType": "The IP address type for the API Gateway endpoint\\. \n*Valid values*: `ipv4` or `dualstack` \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`IpAddressType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html#cfn-apigateway-restapi-endpointconfiguration-ipaddresstype) property of the `AWS::ApiGateway::RestApi` `EndpointConfiguration` data type\\."
5759
},
5860
"sam-property-api-lambdarequestauthorizationidentity": {
5961
"Context": "Converts the given context strings to the mapping expressions of format `context.contextString`\\. \n*Type*: List \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
@@ -799,4 +801,4 @@
799801
"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\\."
800802
}
801803
}
802-
}
804+
}

samtranslator/model/api/api_generator.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ def _construct_stage(
471471

472472
return stage
473473

474-
def _construct_api_domain( # noqa: PLR0912, PLR0915
474+
def _construct_api_domain( # noqa: PLR0912, PLR0915 (too many branches/statements)
475475
self, rest_api: ApiGatewayRestApi, route53_record_set_groups: Any
476476
) -> ApiDomainResponse:
477477
"""
@@ -512,6 +512,11 @@ def _construct_api_domain( # noqa: PLR0912, PLR0915
512512

513513
domain.EndpointConfiguration = {"Types": [endpoint]}
514514

515+
# Handle IpAddressType if present
516+
ip_address_type = self.domain.get("IpAddressType")
517+
if ip_address_type:
518+
domain.EndpointConfiguration["IpAddressType"] = ip_address_type
519+
515520
mutual_tls_auth = self.domain.get("MutualTlsAuthentication", None)
516521
if mutual_tls_auth:
517522
sam_expect(mutual_tls_auth, self.logical_id, "Domain.MutualTlsAuthentication").to_be_a_map()
@@ -602,7 +607,7 @@ def _construct_api_domain( # noqa: PLR0912, PLR0915
602607

603608
return ApiDomainResponse(domain, basepath_resource_list, record_set_group)
604609

605-
def _construct_api_domain_v2(
610+
def _construct_api_domain_v2( # noqa: PLR0915
606611
self, rest_api: ApiGatewayRestApi, route53_record_set_groups: Any
607612
) -> ApiDomainResponseV2:
608613
"""
@@ -637,6 +642,11 @@ def _construct_api_domain_v2(
637642

638643
domain.EndpointConfiguration = {"Types": [endpoint]}
639644

645+
# Handle IpAddressType if present
646+
ip_address_type = self.domain.get("IpAddressType")
647+
if ip_address_type:
648+
domain.EndpointConfiguration["IpAddressType"] = ip_address_type
649+
640650
self._set_optional_domain_properties(domain)
641651

642652
basepaths: Optional[List[str]] = self._get_basepaths()
@@ -1537,6 +1547,10 @@ def _set_endpoint_configuration(self, rest_api: ApiGatewayRestApi, value: Union[
15371547
rest_api.EndpointConfiguration["VpcEndpointIds"] = value.get("VPCEndpointIds") or value.get(
15381548
"VpcEndpointIds"
15391549
)
1550+
1551+
# Handle IpAddressType if present
1552+
if "IpAddressType" in value:
1553+
rest_api.EndpointConfiguration["IpAddressType"] = value.get("IpAddressType")
15401554
else:
15411555
rest_api.EndpointConfiguration = {"Types": [value]}
15421556
rest_api.Parameters = {"endpointConfigurationTypes": value}

samtranslator/schema/schema.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5622,6 +5622,11 @@
56225622
"AWS::ApiGateway::DomainName.EndpointConfiguration": {
56235623
"additionalProperties": false,
56245624
"properties": {
5625+
"IpAddressType": {
5626+
"markdownDescription": "The IP address types that can invoke this DomainName. Use `ipv4` to allow only IPv4 addresses to invoke this DomainName, or use `dualstack` to allow both IPv4 and IPv6 addresses to invoke this DomainName. For the `PRIVATE` endpoint type, only `dualstack` is supported.",
5627+
"title": "IpAddressType",
5628+
"type": "string"
5629+
},
56255630
"Types": {
56265631
"items": {
56275632
"type": "string"
@@ -6478,6 +6483,11 @@
64786483
"AWS::ApiGateway::RestApi.EndpointConfiguration": {
64796484
"additionalProperties": false,
64806485
"properties": {
6486+
"IpAddressType": {
6487+
"markdownDescription": "The IP address types that can invoke an API (RestApi). Use `ipv4` to allow only IPv4 addresses to invoke an API, or use `dualstack` to allow both IPv4 and IPv6 addresses to invoke an API. For the `PRIVATE` endpoint type, only `dualstack` is supported.",
6488+
"title": "IpAddressType",
6489+
"type": "string"
6490+
},
64816491
"Types": {
64826492
"items": {
64836493
"type": "string"
@@ -274565,6 +274575,11 @@
274565274575
"EndpointConfiguration": {
274566274576
"additionalProperties": false,
274567274577
"properties": {
274578+
"IpAddressType": {
274579+
"markdownDescription": "The IP address type for the API Gateway endpoint\\. \n*Valid values*: `ipv4` or `dualstack` \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`IpAddressType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html#cfn-apigateway-restapi-endpointconfiguration-ipaddresstype) property of the `AWS::ApiGateway::RestApi` `EndpointConfiguration` data type\\.",
274580+
"title": "IpAddressType",
274581+
"type": "string"
274582+
},
274568274583
"Type": {
274569274584
"items": {
274570274585
"type": "string"
@@ -277056,6 +277071,11 @@
277056277071
"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\\. \n*Valid values*: `REGIONAL` or `EDGE` \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\\.",
277057277072
"title": "EndpointConfiguration"
277058277073
},
277074+
"IpAddressType": {
277075+
"markdownDescription": "The IP address types that can invoke this DomainName. Use `ipv4` to allow only IPv4 addresses to invoke this DomainName, or use `dualstack` to allow both IPv4 and IPv6 addresses to invoke this DomainName. For the `PRIVATE` endpoint type, only `dualstack` is supported. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`IpAddressType`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-domainname-endpointconfiguration.html#cfn-apigateway-domainname-endpointconfiguration-ipaddresstype) property of an `AWS::ApiGateway::DomainName.EndpointConfiguration` resource.",
277076+
"title": "IpAddressType",
277077+
"type": "string"
277078+
},
277059277079
"MutualTlsAuthentication": {
277060277080
"$ref": "#/definitions/AWS::ApiGateway::DomainName.MutualTlsAuthentication",
277061277081
"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-apigateway-domainname.html#cfn-apigateway-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-apigateway-domainname.html#cfn-apigateway-domainname-mutualtlsauthentication) property of an `AWS::ApiGateway::DomainName` resource\\.",

0 commit comments

Comments
 (0)