Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/globals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Currently, the following resources and properties are being supported:
AccessLogSettings:
Tags:
DefaultRouteSettings:
RouteSettings:
Domain:

SimpleTable:
Expand Down
4 changes: 4 additions & 0 deletions samtranslator/model/api/http_api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(
auth=None,
cors_configuration=None,
access_log_settings=None,
route_settings=None,
default_route_settings=None,
resource_attributes=None,
passthrough_resource_attributes=None,
Expand Down Expand Up @@ -73,6 +74,7 @@ def __init__(
self.cors_configuration = cors_configuration
self.tags = tags
self.access_log_settings = access_log_settings
self.route_settings = route_settings
self.default_route_settings = default_route_settings
self.resource_attributes = resource_attributes
self.passthrough_resource_attributes = passthrough_resource_attributes
Expand Down Expand Up @@ -470,6 +472,7 @@ def _construct_stage(self):
and not self.stage_variables
and not self.access_log_settings
and not self.default_route_settings
and not self.route_settings
):
return

Expand All @@ -490,6 +493,7 @@ def _construct_stage(self):
stage.AccessLogSettings = self.access_log_settings
stage.DefaultRouteSettings = self.default_route_settings
stage.AutoDeploy = True
stage.RouteSettings = self.route_settings

return stage

Expand Down
1 change: 1 addition & 0 deletions samtranslator/model/apigatewayv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ApiGatewayV2Stage(Resource):
property_types = {
"AccessLogSettings": PropertyType(False, is_type(dict)),
"DefaultRouteSettings": PropertyType(False, is_type(dict)),
"RouteSettings": PropertyType(False, is_type(dict)),
"ClientCertificateId": PropertyType(False, is_str()),
"Description": PropertyType(False, is_str()),
"ApiId": PropertyType(True, is_str()),
Expand Down
1 change: 1 addition & 0 deletions samtranslator/model/eventsources/push.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,7 @@ class HttpApi(PushEventSource):
"Stage": PropertyType(False, is_str()),
"Auth": PropertyType(False, is_type(dict)),
"TimeoutInMillis": PropertyType(False, is_type(int)),
"RouteSettings": PropertyType(False, is_type(dict)),
}

def resources_to_link(self, resources):
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 @@ -876,6 +876,7 @@ class SamHttpApi(SamResourceMacro):
"AccessLogSettings": PropertyType(False, is_type(dict)),
"DefaultRouteSettings": PropertyType(False, is_type(dict)),
"Auth": PropertyType(False, is_type(dict)),
"RouteSettings": PropertyType(False, is_type(dict)),
"Domain": PropertyType(False, is_type(dict)),
}

Expand Down Expand Up @@ -910,6 +911,7 @@ def to_cloudformation(self, **kwargs):
auth=self.Auth,
cors_configuration=self.CorsConfiguration,
access_log_settings=self.AccessLogSettings,
route_settings=self.RouteSettings,
default_route_settings=self.DefaultRouteSettings,
resource_attributes=self.resource_attributes,
passthrough_resource_attributes=self.get_passthrough_resource_attributes(),
Expand Down
13 changes: 12 additions & 1 deletion samtranslator/plugins/api/implicit_api_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ def _add_api_to_swagger(self, event_id, event_properties, template):
if isinstance(api_id, dict) or not template.get(api_id):
raise InvalidEventException(
event_id,
"RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource " "in same template",
self.api_id_property
+ " must be a valid reference to an '"
+ self._get_api_resource_type_name()
+ "' resource in same template.",
)

# Make sure Swagger is valid
Expand Down Expand Up @@ -343,3 +346,11 @@ def _generate_implicit_api_resource(self):
raise NotImplementedError(
"Method _setup_api_properties() must be implemented in a " "subclass of ImplicitApiPlugin"
)

def _get_api_resource_type_name(self):
"""
Returns the type of API resource
"""
raise NotImplementedError(
"Method _setup_api_properties() must be implemented in a " "subclass of ImplicitApiPlugin"
)
43 changes: 43 additions & 0 deletions samtranslator/plugins/api/implicit_http_api_plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import six

from samtranslator.model.intrinsics import make_conditional
from samtranslator.model.naming import GeneratedLogicalId
from samtranslator.plugins.api.implicit_api_plugin import ImplicitApiPlugin
from samtranslator.public.open_api import OpenApiEditor
Expand Down Expand Up @@ -88,6 +89,8 @@ def _process_api_events(self, function, api_events, template, condition=None):
method_conditions[method] = condition

self._add_api_to_swagger(logicalId, event_properties, template)
if "RouteSettings" in event_properties:
self._add_route_settings_to_api(logicalId, event_properties, template, condition)
api_events[logicalId] = event

# We could have made changes to the Events structure. Write it back to function
Expand Down Expand Up @@ -116,6 +119,46 @@ def _get_api_definition_from_editor(self, editor):
"""
return editor.openapi

def _get_api_resource_type_name(self):
"""
Returns the type of API resource
"""
return "AWS::Serverless::HttpApi"

def _add_route_settings_to_api(self, event_id, event_properties, template, condition):
"""
Adds the RouteSettings for this path/method from the given event to the RouteSettings configuration
on the AWS::Serverless::HttpApi that this refers to.

:param string event_id: LogicalId of the event
:param dict event_properties: Properties of the event
:param SamTemplate template: SAM Template to search for Serverless::HttpApi resources
:param string condition: Condition on this HttpApi event (if any)
"""

api_id = self._get_api_id(event_properties)
resource = template.get(api_id)

path = event_properties["Path"]
method = event_properties["Method"]

# Route should be in format "METHOD /path" or just "/path" if the ANY method is used
route = "{} {}".format(method.upper(), path)
if method == OpenApiEditor._X_ANY_METHOD:
route = path

# Handle Resource-level conditions if necessary
api_route_settings = resource.properties.get("RouteSettings", {})
event_route_settings = event_properties.get("RouteSettings", {})
if condition:
event_route_settings = make_conditional(condition, event_properties.get("RouteSettings", {}))

# Merge event-level and api-level RouteSettings properties
api_route_settings.setdefault(route, {})
api_route_settings[route].update(event_route_settings)
resource.properties["RouteSettings"] = api_route_settings
template.set(api_id, resource)


class ImplicitHttpApiResource(SamResource):
"""
Expand Down
6 changes: 6 additions & 0 deletions samtranslator/plugins/api/implicit_rest_api_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ def _get_api_definition_from_editor(self, editor):
"""
return editor.swagger

def _get_api_resource_type_name(self):
"""
Returns the type of API resource
"""
return "AWS::Serverless::Api"


class ImplicitApiResource(SamResource):
"""
Expand Down
1 change: 1 addition & 0 deletions samtranslator/plugins/globals/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Globals(object):
"CorsConfiguration",
"DefaultRouteSettings",
"Domain",
"RouteSettings",
],
SamResourceType.SimpleTable.value: ["SSESpecification"],
}
Expand Down
13 changes: 13 additions & 0 deletions tests/translator/input/http_api_explicit_stage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ Parameters:
CorsParam:
Type: String
Default: True
Globals:
HttpApi:
RouteSettings:
"$default":
DataTraceEnabled: True
ThrottlingBurstLimit: 100
Resources:
HttpApiFunction:
Type: AWS::Serverless::Function
Expand All @@ -14,10 +20,17 @@ Resources:
Type: HttpApi
Properties:
ApiId: !Ref MyApi
RouteSettings:
ThrottlingBurstLimit: 300
LoggingLevel: INFO
MyApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: Prod
RouteSettings:
"$default":
ThrottlingBurstLimit: 200
ThrottlingRateLimit: 0.7
AccessLogSettings:
DestinationArn: arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName
Format: $context.requestId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ Conditions:
- false
Globals:
HttpApi:
RouteSettings:
"GET /sub":
ThrottlingBurstLimit: 100
Auth:
Authorizers:
oauth2:
Expand All @@ -73,6 +76,8 @@ Resources:
HttpApiEvent:
Type: HttpApi
Properties:
RouteSettings:
ThrottlingBurstLimit: 200
Path: /sub
Method: get
helloworld1099:
Expand All @@ -89,6 +94,8 @@ Resources:
HttpApiEvent:
Type: HttpApi
Properties:
RouteSettings:
ThrottlingBurstLimit: 200
Auth:
Authorizer: oauth2
HttpApiEvent2:
Expand Down
40 changes: 24 additions & 16 deletions tests/translator/output/aws-cn/http_api_explicit_stage.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"Parameters": {
"CorsParam": {
"Default": true,
"Default": true,
"Type": "String"
}
},
},
"Resources": {
"HttpApiFunctionSimpleCasePermission": {
"Type": "AWS::Lambda::Permission",
Expand Down Expand Up @@ -41,7 +41,7 @@
"Arn"
]
},
"Runtime": "nodejs12.x",
"Runtime": "nodejs12.x",
"Tags": [
{
"Value": "SAM",
Expand All @@ -53,23 +53,28 @@
"MyApiProdStage": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"AutoDeploy": true,
"ApiId": {
"Ref": "MyApi"
},
"AutoDeploy": true,
"StageName": "Prod",
"StageName": "Prod",
"AccessLogSettings": {
"DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName",
"DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName",
"Format": "$context.requestId"
},
"RouteSettings": {
"$default": {
"ThrottlingRateLimit": 0.7,
"DataTraceEnabled": true,
"ThrottlingBurstLimit": 300,
"LoggingLevel": "INFO"
}
}
}
},
"HttpApiFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"ManagedPolicyArns": [
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
Expand All @@ -86,6 +91,9 @@
}
]
},
"ManagedPolicyArns": [
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
"Tags": [
{
"Value": "SAM",
Expand All @@ -103,12 +111,7 @@
"title": {
"Ref": "AWS::StackName"
}
},
"x-amazon-apigateway-cors": {
"allowOrigins": [
"*"
]
},
},
"paths": {
"$default": {
"x-amazon-apigateway-any-method": {
Expand All @@ -125,6 +128,11 @@
}
}
},
"x-amazon-apigateway-cors": {
"allowOrigins": [
"*"
]
},
"openapi": "3.0.1",
"tags": [
{
Expand All @@ -136,4 +144,4 @@
}
}
}
}
}
Loading