Skip to content

Commit

Permalink
Allow SAM Api and HttpApi to Propagate Tags to Generated Resources
Browse files Browse the repository at this point in the history
  • Loading branch information
GavinZZ committed May 31, 2023
1 parent 079ca49 commit 5b5d8a8
Show file tree
Hide file tree
Showing 22 changed files with 1,085 additions and 4 deletions.
2 changes: 2 additions & 0 deletions samtranslator/internal/schema_source/aws_serverless_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ class Properties(BaseModel):
OpenApiVersion: Optional[OpenApiVersion] = properties("OpenApiVersion")
StageName: SamIntrinsicable[str] = properties("StageName")
Tags: Optional[DictStrAny] = properties("Tags")
PropagateTags: Optional[bool] # TODO: add docs
TracingEnabled: Optional[TracingEnabled] = passthrough_prop(
PROPERTIES_STEM,
"TracingEnabled",
Expand Down Expand Up @@ -373,6 +374,7 @@ class Globals(BaseModel):
OpenApiVersion: Optional[OpenApiVersion] = properties("OpenApiVersion")
Domain: Optional[Domain] = properties("Domain")
AlwaysDeploy: Optional[AlwaysDeploy] = properties("AlwaysDeploy")
PropagateTags: Optional[bool] # TODO: add docs


class Resource(ResourceAttributes):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class Properties(BaseModel):
StageName: Optional[PassThroughProp] = properties("StageName")
StageVariables: Optional[StageVariables] = properties("StageVariables")
Tags: Optional[Tags] = properties("Tags")
PropagateTags: Optional[bool] # TODO: add docs
Name: Optional[PassThroughProp] = properties("Name")


Expand All @@ -140,6 +141,7 @@ class Globals(BaseModel):
Domain: Optional[Domain] = properties("Domain")
CorsConfiguration: Optional[CorsConfigurationType] = properties("CorsConfiguration")
DefaultRouteSettings: Optional[DefaultRouteSettings] = properties("DefaultRouteSettings")
PropagateTags: Optional[bool] # TODO: add docs


class Resource(ResourceAttributes):
Expand Down
19 changes: 19 additions & 0 deletions samtranslator/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,25 @@ def _construct_tag_list(
# customer's knowledge.
return get_tag_list(sam_tag) + get_tag_list(additional_tags) + get_tag_list(tags)

def propagate_tags(
self, propagate_tags: Optional[bool], resources: List[Resource], tags: Optional[Dict[str, Any]]
) -> None:
"""
Propagates tags to the resources.
:param resources: List of resources
:param tags: dictionary of tags to propagate to the resources.
:return: None
"""
if not propagate_tags:
return

tags_list = get_tag_list(tags)
for resource in resources:
if "Tags" in resource.property_types:
resource.Tags = tags_list

def _check_tag(self, reserved_tag_name, tags): # type: ignore[no-untyped-def]
if reserved_tag_name in tags:
raise InvalidResourceException(
Expand Down
5 changes: 5 additions & 0 deletions samtranslator/model/apigateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ApiGatewayRestApi(Resource):
"MinimumCompressionSize": GeneratedProperty(),
"Mode": GeneratedProperty(),
"ApiKeySourceType": GeneratedProperty(),
"Tags": GeneratedProperty(),
}

Body: Optional[Dict[str, Any]]
Expand All @@ -42,6 +43,7 @@ class ApiGatewayRestApi(Resource):
MinimumCompressionSize: Optional[PassThrough]
Mode: Optional[PassThrough]
ApiKeySourceType: Optional[PassThrough]
Tags: Optional[PassThrough]

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

Expand Down Expand Up @@ -214,6 +216,7 @@ class ApiGatewayDomainName(Resource):
"MutualTlsAuthentication": GeneratedProperty(),
"SecurityPolicy": GeneratedProperty(),
"CertificateArn": GeneratedProperty(),
"Tags": GeneratedProperty(),
"OwnershipVerificationCertificateArn": GeneratedProperty(),
}

Expand All @@ -223,6 +226,7 @@ class ApiGatewayDomainName(Resource):
MutualTlsAuthentication: Optional[Dict[str, Any]]
SecurityPolicy: Optional[PassThrough]
CertificateArn: Optional[PassThrough]
Tags: Optional[PassThrough]
OwnershipVerificationCertificateArn: Optional[PassThrough]


Expand Down Expand Up @@ -266,6 +270,7 @@ class ApiGatewayApiKey(Resource):
"Enabled": GeneratedProperty(),
"GenerateDistinctId": GeneratedProperty(),
"Name": GeneratedProperty(),
"Tags": GeneratedProperty(),
"StageKeys": GeneratedProperty(),
"Value": GeneratedProperty(),
}
Expand Down
1 change: 1 addition & 0 deletions samtranslator/model/apigatewayv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ApiGatewayV2HttpApi(Resource):
"FailOnWarnings": GeneratedProperty(),
"DisableExecuteApiEndpoint": GeneratedProperty(),
"BasePath": GeneratedProperty(),
"Tags": GeneratedProperty(),
"CorsConfiguration": GeneratedProperty(),
}

Expand Down
14 changes: 12 additions & 2 deletions samtranslator/model/sam_resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" SAM macro definitions """
""" SAM macro definitions """
import copy
from contextlib import suppress
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
Expand Down Expand Up @@ -1155,6 +1155,7 @@ class SamApi(SamResourceMacro):
"Name": PropertyType(False, one_of(IS_STR, IS_DICT)),
"StageName": PropertyType(True, one_of(IS_STR, IS_DICT)),
"Tags": PropertyType(False, IS_DICT),
"PropagateTags": PropertyType(False, IS_BOOL),
"DefinitionBody": PropertyType(False, IS_DICT),
"DefinitionUri": PropertyType(False, one_of(IS_STR, IS_DICT)),
"MergeDefinitions": Property(False, IS_BOOL),
Expand Down Expand Up @@ -1185,6 +1186,7 @@ class SamApi(SamResourceMacro):
Name: Optional[Intrinsicable[str]]
StageName: Optional[Intrinsicable[str]]
Tags: Optional[Dict[str, Any]]
PropagateTags: Optional[bool]
DefinitionBody: Optional[Dict[str, Any]]
DefinitionUri: Optional[Intrinsicable[str]]
MergeDefinitions: Optional[bool]
Expand Down Expand Up @@ -1276,7 +1278,11 @@ def to_cloudformation(self, **kwargs) -> List[Resource]: # type: ignore[no-unty
always_deploy=self.AlwaysDeploy,
)

return api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups)
generated_resources = api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups)

self.propagate_tags(self.PropagateTags, generated_resources, self.Tags)

return generated_resources


class SamHttpApi(SamResourceMacro):
Expand All @@ -1293,6 +1299,7 @@ class SamHttpApi(SamResourceMacro):
"Name": PassThroughProperty(False),
"StageName": PropertyType(False, one_of(IS_STR, IS_DICT)),
"Tags": PropertyType(False, IS_DICT),
"PropagateTags": PropertyType(False, IS_BOOL),
"DefinitionBody": PropertyType(False, IS_DICT),
"DefinitionUri": PropertyType(False, one_of(IS_STR, IS_DICT)),
"StageVariables": PropertyType(False, IS_DICT),
Expand All @@ -1310,6 +1317,7 @@ class SamHttpApi(SamResourceMacro):
Name: Optional[Any]
StageName: Optional[Intrinsicable[str]]
Tags: Optional[Dict[str, Any]]
PropagateTags: Optional[bool]
DefinitionBody: Optional[Dict[str, Any]]
DefinitionUri: Optional[Intrinsicable[str]]
StageVariables: Optional[Dict[str, Intrinsicable[str]]]
Expand Down Expand Up @@ -1387,6 +1395,8 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def]
if stage:
resources.append(stage)

self.propagate_tags(self.PropagateTags, resources, self.Tags)

return resources


Expand Down
2 changes: 2 additions & 0 deletions samtranslator/plugins/globals/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Globals:
"OpenApiVersion",
"Domain",
"AlwaysDeploy",
"PropagateTags",
],
SamResourceType.HttpApi.value: [
"Auth",
Expand All @@ -87,6 +88,7 @@ class Globals:
"Domain",
"RouteSettings",
"FailOnWarnings",
"PropagateTags",
],
SamResourceType.SimpleTable.value: ["SSESpecification"],
}
Expand Down
16 changes: 16 additions & 0 deletions samtranslator/schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -239456,6 +239456,10 @@
"markdownDescription": "Version of OpenApi to use\\. This can either be `2.0` for the Swagger specification, or one of the OpenApi 3\\.0 versions, like `3.0.1`\\. For more information about OpenAPI, see the [OpenAPI Specification](https://swagger.io/specification/)\\. \n AWS SAM creates a stage called `Stage` by default\\. Setting this property to any valid value will prevent the creation of the stage `Stage`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "OpenApiVersion"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"TracingEnabled": {
"markdownDescription": "Indicates whether active tracing with X\\-Ray is enabled for the stage\\. For more information about X\\-Ray, see [Tracing user requests to REST APIs using X\\-Ray](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-xray.html) in the *API Gateway Developer Guide*\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`TracingEnabled`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-stage.html#cfn-apigateway-stage-tracingenabled) property of an `AWS::ApiGateway::Stage` resource\\.",
"title": "TracingEnabled",
Expand Down Expand Up @@ -239649,6 +239653,10 @@
"markdownDescription": "Version of OpenApi to use\\. This can either be `2.0` for the Swagger specification, or one of the OpenApi 3\\.0 versions, like `3.0.1`\\. For more information about OpenAPI, see the [OpenAPI Specification](https://swagger.io/specification/)\\. \n AWS SAM creates a stage called `Stage` by default\\. Setting this property to any valid value will prevent the creation of the stage `Stage`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "OpenApiVersion"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"StageName": {
"anyOf": [
{
Expand Down Expand Up @@ -241673,6 +241681,10 @@
"markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.",
"title": "FailOnWarnings"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"RouteSettings": {
"allOf": [
{
Expand Down Expand Up @@ -241797,6 +241809,10 @@
"markdownDescription": "The name of the HTTP API resource\\. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "Name"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"RouteSettings": {
"allOf": [
{
Expand Down
16 changes: 16 additions & 0 deletions schema_source/sam.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3425,6 +3425,10 @@
"markdownDescription": "Version of OpenApi to use\\. This can either be `2.0` for the Swagger specification, or one of the OpenApi 3\\.0 versions, like `3.0.1`\\. For more information about OpenAPI, see the [OpenAPI Specification](https://swagger.io/specification/)\\. \n AWS SAM creates a stage called `Stage` by default\\. Setting this property to any valid value will prevent the creation of the stage `Stage`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "OpenApiVersion"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"TracingEnabled": {
"__samPassThrough": {
"markdownDescriptionOverride": "Indicates whether active tracing with X\\-Ray is enabled for the stage\\. For more information about X\\-Ray, see [Tracing user requests to REST APIs using X\\-Ray](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-xray.html) in the *API Gateway Developer Guide*\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`TracingEnabled`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-stage.html#cfn-apigateway-stage-tracingenabled) property of an `AWS::ApiGateway::Stage` resource\\.",
Expand Down Expand Up @@ -3791,6 +3795,10 @@
"markdownDescription": "Version of OpenApi to use\\. This can either be `2.0` for the Swagger specification, or one of the OpenApi 3\\.0 versions, like `3.0.1`\\. For more information about OpenAPI, see the [OpenAPI Specification](https://swagger.io/specification/)\\. \n AWS SAM creates a stage called `Stage` by default\\. Setting this property to any valid value will prevent the creation of the stage `Stage`\\. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "OpenApiVersion"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"StageName": {
"anyOf": [
{
Expand Down Expand Up @@ -6204,6 +6212,10 @@
"markdownDescription": "Specifies whether to roll back the HTTP API creation \\(`true`\\) or not \\(`false`\\) when a warning is encountered\\. The default value is `false`\\. \n*Type*: Boolean \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings) property of an `AWS::ApiGatewayV2::Api` resource\\.",
"title": "FailOnWarnings"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"RouteSettings": {
"allOf": [
{
Expand Down Expand Up @@ -6328,6 +6340,10 @@
"markdownDescription": "The name of the HTTP API resource\\. \nWhen you specify `Name`, AWS SAM will modify the HTTP API resource's OpenAPI definition by setting the `title` field\\. The following scenarios will result in an error: \n+ The `DefinitionBody` property is specified with the `title` field set in the Open API definition \u2013 This results in a conflict of the `title` field that AWS SAM won't resolve\\.\n+ The `DefinitionUri` property is specified \u2013 AWS SAM won't modify an Open API definition that is retrieved from Amazon S3\\.\n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent\\.",
"title": "Name"
},
"PropagateTags": {
"title": "Propagatetags",
"type": "boolean"
},
"RouteSettings": {
"allOf": [
{
Expand Down
17 changes: 17 additions & 0 deletions tests/translator/input/api_with_propagate_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Parameters:
TagValueParam:
Type: String
Default: value

Resources:
MyApiWithPropagateTags:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
PropagateTags: true
Tags:
TagKey1: TagValue1
TagKey2: ''
TagKey3:
Ref: TagValueParam
TagKey4: '123'
12 changes: 12 additions & 0 deletions tests/translator/input/api_with_propagate_tags_globals.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Globals:
Api:
PropagateTags: true

Resources:
MyApiWithPropagateTags:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Tags:
TagKey1: TagValue1
TagKey2: ''
32 changes: 32 additions & 0 deletions tests/translator/input/httpapi_with_propagate_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Globals:
HttpApi:
RouteSettings:
$default:
DataTraceEnabled: true
ThrottlingBurstLimit: 100
FailOnWarnings: true
Resources:
MyApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: Prod
PropagateTags: true
Domain:
DomainName: admin.one.amazon.com
CertificateArn: arn::cert::abc
EndpointConfiguration: REGIONAL
Route53:
HostedZoneId: abc123456
StageVariables:
VarName: VarValue
Tags:
TagKey1: Value1
TagKey2: Value2
RouteSettings:
$default:
ThrottlingBurstLimit: 200
ThrottlingRateLimit: 0.7
AccessLogSettings:
DestinationArn: random-arn
Format: $context.requestId
CorsConfiguration: true
Loading

0 comments on commit 5b5d8a8

Please sign in to comment.