Skip to content

Commit 5f7c1ce

Browse files
authored
feat: Add support for the FailOnWarnings property on AWS::Serverless::Api (#2417)
* initial logic for supporting the FailOnWarnings property * initial unit tests added * initial pass at integration test logic * parameterised FailOnWarnings value in api_with_fail_on_warnings.yaml * api_with_fail_on_warnings test added to tests/translator/test_translator.py * reverted change in tests/translator/test_translator.py
1 parent e62dcfc commit 5f7c1ce

File tree

13 files changed

+537
-1
lines changed

13 files changed

+537
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from parameterized import parameterized
2+
3+
from integration.helpers.base_test import BaseTest
4+
5+
6+
class TestApiWithFailOnWarnings(BaseTest):
7+
@parameterized.expand(
8+
[
9+
("combination/api_with_fail_on_warnings", True),
10+
("combination/api_with_fail_on_warnings", False),
11+
]
12+
)
13+
def test_end_point_configuration(self, file_name, disable_value):
14+
parameters = [
15+
{
16+
"ParameterKey": "FailOnWarningsValue",
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+
api_result = apigw_client.get_rest_api(restApiId=rest_api_id)
29+
self.assertEqual(api_result["ResponseMetadata"]["HTTPStatusCode"], 200)
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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Parameters:
2+
FailOnWarningsValue:
3+
Type: String
4+
AllowedValues: [true, false]
5+
6+
Resources:
7+
RestApiGateway:
8+
Type: AWS::Serverless::Api
9+
Properties:
10+
StageName: Prod
11+
FailOnWarnings:
12+
Ref: FailOnWarningsValue
13+
14+
RestApiFunction:
15+
Type: AWS::Serverless::Function
16+
Properties:
17+
InlineCode: |
18+
exports.handler = async (event) => {
19+
const response = {
20+
statusCode: 200,
21+
body: JSON.stringify('Hello from Lambda!'),
22+
};
23+
return response;
24+
};
25+
Handler: index.handler
26+
Runtime: nodejs12.x
27+
Events:
28+
Iam:
29+
Type: Api
30+
Properties:
31+
RestApiId:
32+
Ref: RestApiGateway
33+
Method: GET
34+
Path: /

samtranslator/model/api/api_generator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def __init__(
181181
open_api_version=None,
182182
models=None,
183183
domain=None,
184+
fail_on_warnings=None,
184185
description=None,
185186
mode=None,
186187
api_key_source_type=None,
@@ -232,6 +233,7 @@ def __init__(
232233
self.remove_extra_stage = open_api_version
233234
self.models = models
234235
self.domain = domain
236+
self.fail_on_warnings = fail_on_warnings
235237
self.description = description
236238
self.shared_api_usage_plan = shared_api_usage_plan
237239
self.template_conditions = template_conditions
@@ -277,6 +279,9 @@ def _construct_rest_api(self):
277279
self._add_binary_media_types()
278280
self._add_models()
279281

282+
if self.fail_on_warnings:
283+
rest_api.FailOnWarnings = self.fail_on_warnings
284+
280285
if self.disable_execute_api_endpoint is not None:
281286
self._add_endpoint_extension()
282287

samtranslator/model/api/http_api_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(
4848
resource_attributes=None,
4949
passthrough_resource_attributes=None,
5050
domain=None,
51-
fail_on_warnings=False,
51+
fail_on_warnings=None,
5252
description=None,
5353
disable_execute_api_endpoint=None,
5454
):

samtranslator/model/sam_resources.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ class SamApi(SamResourceMacro):
10731073
"OpenApiVersion": PropertyType(False, is_str()),
10741074
"Models": PropertyType(False, is_type(dict)),
10751075
"Domain": PropertyType(False, is_type(dict)),
1076+
"FailOnWarnings": PropertyType(False, is_type(bool)),
10761077
"Description": PropertyType(False, is_str()),
10771078
"Mode": PropertyType(False, is_str()),
10781079
"DisableExecuteApiEndpoint": PropertyType(False, is_type(bool)),
@@ -1136,6 +1137,7 @@ def to_cloudformation(self, **kwargs):
11361137
open_api_version=self.OpenApiVersion,
11371138
models=self.Models,
11381139
domain=self.Domain,
1140+
fail_on_warnings=self.FailOnWarnings,
11391141
description=self.Description,
11401142
mode=self.Mode,
11411143
api_key_source_type=self.ApiKeySourceType,

samtranslator/validator/sam_schema/definitions/api.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@
117117
"EndpointConfiguration": {
118118
"$ref": "#definitions/AWS::Serverless::Api.EndpointConfiguration"
119119
},
120+
"FailOnWarnings": {
121+
"type": [
122+
"boolean",
123+
"intrinsic"
124+
]
125+
},
120126
"GatewayResponses": {
121127
"$ref": "common.json#definitions/GatewayResponses",
122128
"references": [
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Resources:
2+
ApiGatewayApi:
3+
Type: AWS::Serverless::Api
4+
Properties:
5+
StageName: prod
6+
FailOnWarnings: true
7+
ApiFunction: # Adds a GET api endpoint at "/" to the ApiGatewayApi via an Api event
8+
Type: AWS::Serverless::Function
9+
Properties:
10+
Events:
11+
ApiEvent:
12+
Type: Api
13+
Properties:
14+
Path: /
15+
Method: get
16+
RestApiId:
17+
Ref: ApiGatewayApi
18+
Runtime: python3.7
19+
Handler: index.handler
20+
InlineCode: |
21+
def handler(event, context):
22+
return {'body': 'Hello World!', 'statusCode': 200}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Resources:
2+
ApiGatewayApi:
3+
Type: AWS::Serverless::Api
4+
Properties:
5+
StageName: prod
6+
FailOnWarnings: ''
7+
ApiFunction: # Adds a GET api endpoint at "/" to the ApiGatewayApi via an Api event
8+
Type: AWS::Serverless::Function
9+
Properties:
10+
Events:
11+
ApiEvent:
12+
Type: Api
13+
Properties:
14+
Path: /
15+
Method: get
16+
RestApiId:
17+
Ref: ApiGatewayApi
18+
Runtime: python3.7
19+
Handler: index.handler
20+
InlineCode: |
21+
def handler(event, context):
22+
return {'body': 'Hello World!', 'statusCode': 200}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
{
2+
"Resources": {
3+
"ApiGatewayApi": {
4+
"Type": "AWS::ApiGateway::RestApi",
5+
"Properties": {
6+
"Body": {
7+
"info": {
8+
"version": "1.0",
9+
"title": {
10+
"Ref": "AWS::StackName"
11+
}
12+
},
13+
"paths": {
14+
"/": {
15+
"get": {
16+
"x-amazon-apigateway-integration": {
17+
"httpMethod": "POST",
18+
"type": "aws_proxy",
19+
"uri": {
20+
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations"
21+
}
22+
},
23+
"responses": {}
24+
}
25+
}
26+
},
27+
"swagger": "2.0"
28+
},
29+
"FailOnWarnings": true
30+
}
31+
},
32+
"ApiGatewayApiDeploymentf96bc9abda": {
33+
"Type": "AWS::ApiGateway::Deployment",
34+
"Properties": {
35+
"RestApiId": {
36+
"Ref": "ApiGatewayApi"
37+
},
38+
"Description": "RestApi deployment id: f96bc9abdad53c001153ce8ba04f1667c7b0a004",
39+
"StageName": "Stage"
40+
}
41+
},
42+
"ApiFunctionRole": {
43+
"Type": "AWS::IAM::Role",
44+
"Properties": {
45+
"AssumeRolePolicyDocument": {
46+
"Version": "2012-10-17",
47+
"Statement": [
48+
{
49+
"Action": [
50+
"sts:AssumeRole"
51+
],
52+
"Effect": "Allow",
53+
"Principal": {
54+
"Service": [
55+
"lambda.amazonaws.com"
56+
]
57+
}
58+
}
59+
]
60+
},
61+
"ManagedPolicyArns": [
62+
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
63+
],
64+
"Tags": [
65+
{
66+
"Value": "SAM",
67+
"Key": "lambda:createdBy"
68+
}
69+
]
70+
}
71+
},
72+
"ApiFunction": {
73+
"Type": "AWS::Lambda::Function",
74+
"Properties": {
75+
"Handler": "index.handler",
76+
"Code": {
77+
"ZipFile": "def handler(event, context):\n return {'body': 'Hello World!', 'statusCode': 200}\n"
78+
},
79+
"Role": {
80+
"Fn::GetAtt": [
81+
"ApiFunctionRole",
82+
"Arn"
83+
]
84+
},
85+
"Runtime": "python3.7",
86+
"Tags": [
87+
{
88+
"Value": "SAM",
89+
"Key": "lambda:createdBy"
90+
}
91+
]
92+
}
93+
},
94+
"ApiFunctionApiEventPermissionprod": {
95+
"Type": "AWS::Lambda::Permission",
96+
"Properties": {
97+
"Action": "lambda:InvokeFunction",
98+
"Principal": "apigateway.amazonaws.com",
99+
"FunctionName": {
100+
"Ref": "ApiFunction"
101+
},
102+
"SourceArn": {
103+
"Fn::Sub": [
104+
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/",
105+
{
106+
"__Stage__": "*",
107+
"__ApiId__": {
108+
"Ref": "ApiGatewayApi"
109+
}
110+
}
111+
]
112+
}
113+
}
114+
},
115+
"ApiGatewayApiprodStage": {
116+
"Type": "AWS::ApiGateway::Stage",
117+
"Properties": {
118+
"DeploymentId": {
119+
"Ref": "ApiGatewayApiDeploymentf96bc9abda"
120+
},
121+
"RestApiId": {
122+
"Ref": "ApiGatewayApi"
123+
},
124+
"StageName": "prod"
125+
}
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)