Skip to content

Commit

Permalink
feat: Add support for the FailOnWarnings property on `AWS::Serverle…
Browse files Browse the repository at this point in the history
…ss::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
  • Loading branch information
nialdaly authored Jul 6, 2022
1 parent e62dcfc commit 5f7c1ce
Show file tree
Hide file tree
Showing 13 changed files with 537 additions and 1 deletion.
29 changes: 29 additions & 0 deletions integration/combination/test_api_with_fail_on_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from parameterized import parameterized

from integration.helpers.base_test import BaseTest


class TestApiWithFailOnWarnings(BaseTest):
@parameterized.expand(
[
("combination/api_with_fail_on_warnings", True),
("combination/api_with_fail_on_warnings", False),
]
)
def test_end_point_configuration(self, file_name, disable_value):
parameters = [
{
"ParameterKey": "FailOnWarningsValue",
"ParameterValue": "true" if disable_value else "false",
"UsePreviousValue": False,
"ResolvedValue": "string",
}
]

self.create_and_verify_stack(file_name, parameters)

rest_api_id = self.get_physical_id_by_type("AWS::ApiGateway::RestApi")
apigw_client = self.client_provider.api_client

api_result = apigw_client.get_rest_api(restApiId=rest_api_id)
self.assertEqual(api_result["ResponseMetadata"]["HTTPStatusCode"], 200)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{"LogicalResourceId": "RestApiGateway", "ResourceType": "AWS::ApiGateway::RestApi"},
{"LogicalResourceId": "RestApiGatewayDeployment", "ResourceType": "AWS::ApiGateway::Deployment"},
{"LogicalResourceId": "RestApiGatewayProdStage", "ResourceType": "AWS::ApiGateway::Stage"},
{"LogicalResourceId": "RestApiFunction", "ResourceType": "AWS::Lambda::Function"},
{"LogicalResourceId": "RestApiFunctionIamPermissionProd", "ResourceType": "AWS::Lambda::Permission"},
{"LogicalResourceId": "RestApiFunctionRole", "ResourceType": "AWS::IAM::Role"}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Parameters:
FailOnWarningsValue:
Type: String
AllowedValues: [true, false]

Resources:
RestApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
FailOnWarnings:
Ref: FailOnWarningsValue

RestApiFunction:
Type: AWS::Serverless::Function
Properties:
InlineCode: |
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
Handler: index.handler
Runtime: nodejs12.x
Events:
Iam:
Type: Api
Properties:
RestApiId:
Ref: RestApiGateway
Method: GET
Path: /
5 changes: 5 additions & 0 deletions samtranslator/model/api/api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def __init__(
open_api_version=None,
models=None,
domain=None,
fail_on_warnings=None,
description=None,
mode=None,
api_key_source_type=None,
Expand Down Expand Up @@ -232,6 +233,7 @@ def __init__(
self.remove_extra_stage = open_api_version
self.models = models
self.domain = domain
self.fail_on_warnings = fail_on_warnings
self.description = description
self.shared_api_usage_plan = shared_api_usage_plan
self.template_conditions = template_conditions
Expand Down Expand Up @@ -277,6 +279,9 @@ def _construct_rest_api(self):
self._add_binary_media_types()
self._add_models()

if self.fail_on_warnings:
rest_api.FailOnWarnings = self.fail_on_warnings

if self.disable_execute_api_endpoint is not None:
self._add_endpoint_extension()

Expand Down
2 changes: 1 addition & 1 deletion samtranslator/model/api/http_api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(
resource_attributes=None,
passthrough_resource_attributes=None,
domain=None,
fail_on_warnings=False,
fail_on_warnings=None,
description=None,
disable_execute_api_endpoint=None,
):
Expand Down
2 changes: 2 additions & 0 deletions samtranslator/model/sam_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ class SamApi(SamResourceMacro):
"OpenApiVersion": PropertyType(False, is_str()),
"Models": PropertyType(False, is_type(dict)),
"Domain": PropertyType(False, is_type(dict)),
"FailOnWarnings": PropertyType(False, is_type(bool)),
"Description": PropertyType(False, is_str()),
"Mode": PropertyType(False, is_str()),
"DisableExecuteApiEndpoint": PropertyType(False, is_type(bool)),
Expand Down Expand Up @@ -1136,6 +1137,7 @@ def to_cloudformation(self, **kwargs):
open_api_version=self.OpenApiVersion,
models=self.Models,
domain=self.Domain,
fail_on_warnings=self.FailOnWarnings,
description=self.Description,
mode=self.Mode,
api_key_source_type=self.ApiKeySourceType,
Expand Down
6 changes: 6 additions & 0 deletions samtranslator/validator/sam_schema/definitions/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@
"EndpointConfiguration": {
"$ref": "#definitions/AWS::Serverless::Api.EndpointConfiguration"
},
"FailOnWarnings": {
"type": [
"boolean",
"intrinsic"
]
},
"GatewayResponses": {
"$ref": "common.json#definitions/GatewayResponses",
"references": [
Expand Down
22 changes: 22 additions & 0 deletions tests/translator/input/api_with_fail_on_warnings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
FailOnWarnings: true
ApiFunction: # Adds a GET api endpoint at "/" to the ApiGatewayApi via an Api event
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Type: Api
Properties:
Path: /
Method: get
RestApiId:
Ref: ApiGatewayApi
Runtime: python3.7
Handler: index.handler
InlineCode: |
def handler(event, context):
return {'body': 'Hello World!', 'statusCode': 200}
22 changes: 22 additions & 0 deletions tests/translator/input/error_api_invalid_fail_on_warnings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
FailOnWarnings: ''
ApiFunction: # Adds a GET api endpoint at "/" to the ApiGatewayApi via an Api event
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Type: Api
Properties:
Path: /
Method: get
RestApiId:
Ref: ApiGatewayApi
Runtime: python3.7
Handler: index.handler
InlineCode: |
def handler(event, context):
return {'body': 'Hello World!', 'statusCode': 200}
128 changes: 128 additions & 0 deletions tests/translator/output/api_with_fail_on_warnings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
"Resources": {
"ApiGatewayApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"paths": {
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations"
}
},
"responses": {}
}
}
},
"swagger": "2.0"
},
"FailOnWarnings": true
}
},
"ApiGatewayApiDeploymentf96bc9abda": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "ApiGatewayApi"
},
"Description": "RestApi deployment id: f96bc9abdad53c001153ce8ba04f1667c7b0a004",
"StageName": "Stage"
}
},
"ApiFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
}
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
"Tags": [
{
"Value": "SAM",
"Key": "lambda:createdBy"
}
]
}
},
"ApiFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Handler": "index.handler",
"Code": {
"ZipFile": "def handler(event, context):\n return {'body': 'Hello World!', 'statusCode': 200}\n"
},
"Role": {
"Fn::GetAtt": [
"ApiFunctionRole",
"Arn"
]
},
"Runtime": "python3.7",
"Tags": [
{
"Value": "SAM",
"Key": "lambda:createdBy"
}
]
}
},
"ApiFunctionApiEventPermissionprod": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"Principal": "apigateway.amazonaws.com",
"FunctionName": {
"Ref": "ApiFunction"
},
"SourceArn": {
"Fn::Sub": [
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/",
{
"__Stage__": "*",
"__ApiId__": {
"Ref": "ApiGatewayApi"
}
}
]
}
}
},
"ApiGatewayApiprodStage": {
"Type": "AWS::ApiGateway::Stage",
"Properties": {
"DeploymentId": {
"Ref": "ApiGatewayApiDeploymentf96bc9abda"
},
"RestApiId": {
"Ref": "ApiGatewayApi"
},
"StageName": "prod"
}
}
}
}
Loading

0 comments on commit 5f7c1ce

Please sign in to comment.