Skip to content

Commit db25683

Browse files
authored
merge: release 1.42.0
release: 1.42.0
2 parents e214dac + 5d3ea53 commit db25683

24 files changed

+735
-1
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from parameterized import parameterized
2+
3+
from integration.helpers.base_test import BaseTest
4+
5+
6+
class TestApiWithDisableExecuteApiEndpoint(BaseTest):
7+
@parameterized.expand(
8+
[
9+
("combination/api_with_disable_execute_api_endpoint", True),
10+
("combination/api_with_disable_execute_api_endpoint", False),
11+
]
12+
)
13+
def test_end_point_configuration(self, file_name, disable_value):
14+
parameters = [
15+
{
16+
"ParameterKey": "DisableExecuteApiEndpointValue",
17+
"ParameterValue": "true" if disable_value else "false",
18+
"UsePreviousValue": False,
19+
"ResolvedValue": "string",
20+
}
21+
]
22+
23+
self.create_and_verify_stack(file_name, parameters)
24+
25+
rest_api_id = self.get_physical_id_by_type("AWS::ApiGateway::RestApi")
26+
apigw_client = self.client_provider.api_client
27+
28+
response = apigw_client.get_rest_api(restApiId=rest_api_id)
29+
api_result = response["disableExecuteApiEndpoint"]
30+
self.assertEqual(api_result, disable_value)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{"LogicalResourceId": "RestApiGateway", "ResourceType": "AWS::ApiGateway::RestApi"},
3+
{"LogicalResourceId": "RestApiGatewayDeployment", "ResourceType": "AWS::ApiGateway::Deployment"},
4+
{"LogicalResourceId": "RestApiGatewayProdStage", "ResourceType": "AWS::ApiGateway::Stage"},
5+
{"LogicalResourceId": "RestApiFunction", "ResourceType": "AWS::Lambda::Function"},
6+
{"LogicalResourceId": "RestApiFunctionIamPermissionProd", "ResourceType": "AWS::Lambda::Permission"},
7+
{"LogicalResourceId": "RestApiFunctionRole", "ResourceType": "AWS::IAM::Role"}
8+
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Parameters:
2+
DisableExecuteApiEndpointValue:
3+
Description: Variable to define if client can access default API endpoint.
4+
Type: String
5+
AllowedValues: [true, false]
6+
7+
Resources:
8+
RestApiGateway:
9+
Type: AWS::Serverless::Api
10+
Properties:
11+
StageName: Prod
12+
DisableExecuteApiEndpoint:
13+
Ref: DisableExecuteApiEndpointValue
14+
15+
RestApiFunction:
16+
Type: AWS::Serverless::Function
17+
Properties:
18+
InlineCode: |
19+
exports.handler = async (event) => {
20+
const response = {
21+
statusCode: 200,
22+
body: JSON.stringify('Hello from Lambda!'),
23+
};
24+
return response;
25+
};
26+
Handler: index.handler
27+
Runtime: nodejs12.x
28+
Events:
29+
Iam:
30+
Type: Api
31+
Properties:
32+
RestApiId: !Ref RestApiGateway
33+
Method: GET
34+
Path: /
35+
Outputs:
36+
ApiUrl:
37+
Description: "API endpoint URL for Prod environment"
38+
Value:
39+
Fn::Sub: 'https://${RestApiGateway}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prod/'

samtranslator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.41.0"
1+
__version__ = "1.42.0"

samtranslator/model/api/api_generator.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ def __init__(
170170
method_settings=None,
171171
binary_media=None,
172172
minimum_compression_size=None,
173+
disable_execute_api_endpoint=None,
173174
cors=None,
174175
auth=None,
175176
gateway_responses=None,
@@ -218,6 +219,7 @@ def __init__(
218219
self.method_settings = method_settings
219220
self.binary_media = binary_media
220221
self.minimum_compression_size = minimum_compression_size
222+
self.disable_execute_api_endpoint = disable_execute_api_endpoint
221223
self.cors = cors
222224
self.auth = auth
223225
self.gateway_responses = gateway_responses
@@ -290,8 +292,27 @@ def _construct_rest_api(self):
290292
if self.mode:
291293
rest_api.Mode = self.mode
292294

295+
if self.disable_execute_api_endpoint is not None:
296+
self._add_endpoint_extension()
297+
293298
return rest_api
294299

300+
def _add_endpoint_extension(self):
301+
"""Add disableExecuteApiEndpoint if it is set in SAM
302+
Note:
303+
If neither DefinitionUri nor DefinitionBody are specified,
304+
SAM will generate a openapi definition body based on template configuration.
305+
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-definitionbody
306+
For this reason, we always put DisableExecuteApiEndpoint into openapi object irrespective of origin of DefinitionBody.
307+
"""
308+
if self.disable_execute_api_endpoint and not self.definition_body:
309+
raise InvalidResourceException(
310+
self.logical_id, "DisableExecuteApiEndpoint works only within 'DefinitionBody' property."
311+
)
312+
editor = SwaggerEditor(self.definition_body)
313+
editor.add_disable_execute_api_endpoint_extension(self.disable_execute_api_endpoint)
314+
self.definition_body = editor.swagger
315+
295316
def _construct_body_s3_dict(self):
296317
"""Constructs the RestApi's `BodyS3Location property`_, from the SAM Api's DefinitionUri property.
297318
@@ -444,6 +465,9 @@ def _construct_api_domain(self, rest_api):
444465
if self.domain.get("SecurityPolicy", None):
445466
domain.SecurityPolicy = self.domain["SecurityPolicy"]
446467

468+
if self.domain.get("OwnershipVerificationCertificateArn", None):
469+
domain.OwnershipVerificationCertificateArn = self.domain["OwnershipVerificationCertificateArn"]
470+
447471
# Create BasepathMappings
448472
if self.domain.get("BasePath") and isinstance(self.domain.get("BasePath"), string_types):
449473
basepaths = [self.domain.get("BasePath")]

samtranslator/model/api/http_api_generator.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ def _construct_api_domain(self, http_api):
253253
"EndpointConfiguration for Custom Domains must be one of {}.".format(["REGIONAL"]),
254254
)
255255
domain_config["EndpointType"] = endpoint
256+
257+
if self.domain.get("OwnershipVerificationCertificateArn", None):
258+
domain_config["OwnershipVerificationCertificateArn"] = self.domain.get(
259+
"OwnershipVerificationCertificateArn"
260+
)
261+
256262
domain_config["CertificateArn"] = self.domain.get("CertificateArn")
257263
if self.domain.get("SecurityPolicy", None):
258264
domain_config["SecurityPolicy"] = self.domain.get("SecurityPolicy")

samtranslator/model/apigateway.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class ApiGatewayDomainName(Resource):
169169
"MutualTlsAuthentication": PropertyType(False, is_type(dict)),
170170
"SecurityPolicy": PropertyType(False, is_str()),
171171
"CertificateArn": PropertyType(False, is_str()),
172+
"OwnershipVerificationCertificateArn": PropertyType(False, is_str()),
172173
}
173174

174175

samtranslator/model/eventsources/pull.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class PullEventSource(ResourceMacro):
2121
:cvar str policy_arn: The ARN of the AWS managed role policy corresponding to this pull event source
2222
"""
2323

24+
# Event types that support `FilterCriteria`, stored as a list to keep the alphabetical order
25+
RESOURCE_TYPES_WITH_EVENT_FILTERING = ["DynamoDB", "Kinesis", "SQS"]
26+
2427
resource_type = None
2528
requires_stream_queue_broker = True
2629
property_types = {
@@ -43,6 +46,7 @@ class PullEventSource(ResourceMacro):
4346
"TumblingWindowInSeconds": PropertyType(False, is_type(int)),
4447
"FunctionResponseTypes": PropertyType(False, is_type(list)),
4548
"KafkaBootstrapServers": PropertyType(False, is_type(list)),
49+
"FilterCriteria": PropertyType(False, is_type(dict)),
4650
}
4751

4852
def get_policy_arn(self):
@@ -102,6 +106,8 @@ def to_cloudformation(self, **kwargs):
102106
lambda_eventsourcemapping.SourceAccessConfigurations = self.SourceAccessConfigurations
103107
lambda_eventsourcemapping.TumblingWindowInSeconds = self.TumblingWindowInSeconds
104108
lambda_eventsourcemapping.FunctionResponseTypes = self.FunctionResponseTypes
109+
lambda_eventsourcemapping.FilterCriteria = self.FilterCriteria
110+
self._validate_filter_criteria()
105111

106112
if self.KafkaBootstrapServers:
107113
lambda_eventsourcemapping.SelfManagedEventSource = {
@@ -169,6 +175,20 @@ def _link_policy(self, role, destination_config_policy=None):
169175
if not destination_config_policy.get("PolicyDocument") in [d["PolicyDocument"] for d in role.Policies]:
170176
role.Policies.append(destination_config_policy)
171177

178+
def _validate_filter_criteria(self):
179+
if not self.FilterCriteria or is_intrinsic(self.FilterCriteria):
180+
return
181+
if self.resource_type not in self.RESOURCE_TYPES_WITH_EVENT_FILTERING:
182+
raise InvalidEventException(
183+
self.relative_id,
184+
"FilterCriteria is only available for {} events.".format(
185+
", ".join(self.RESOURCE_TYPES_WITH_EVENT_FILTERING)
186+
),
187+
)
188+
# FilterCriteria is either empty or only has "Filters"
189+
if list(self.FilterCriteria.keys()) not in [[], ["Filters"]]:
190+
raise InvalidEventException(self.relative_id, "FilterCriteria field has a wrong format")
191+
172192

173193
class Kinesis(PullEventSource):
174194
"""Kinesis event source."""

samtranslator/model/lambda_.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class LambdaEventSourceMapping(Resource):
7979
"TumblingWindowInSeconds": PropertyType(False, is_type(int)),
8080
"FunctionResponseTypes": PropertyType(False, is_type(list)),
8181
"SelfManagedEventSource": PropertyType(False, is_type(dict)),
82+
"FilterCriteria": PropertyType(False, is_type(dict)),
8283
}
8384

8485
runtime_attrs = {"name": lambda self: ref(self.logical_id)}

samtranslator/model/sam_resources.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ class SamApi(SamResourceMacro):
878878
"Domain": PropertyType(False, is_type(dict)),
879879
"Description": PropertyType(False, is_str()),
880880
"Mode": PropertyType(False, is_str()),
881+
"DisableExecuteApiEndpoint": PropertyType(False, is_type(bool)),
881882
}
882883

883884
referable_properties = {
@@ -925,6 +926,7 @@ def to_cloudformation(self, **kwargs):
925926
method_settings=self.MethodSettings,
926927
binary_media=self.BinaryMediaTypes,
927928
minimum_compression_size=self.MinimumCompressionSize,
929+
disable_execute_api_endpoint=self.DisableExecuteApiEndpoint,
928930
cors=self.Cors,
929931
auth=self.Auth,
930932
gateway_responses=self.GatewayResponses,

0 commit comments

Comments
 (0)