Skip to content

Commit cb20917

Browse files
authored
fix: Fix Propagate Tags when Tags is defined in Globals (#3284)
1 parent f27528d commit cb20917

File tree

6 files changed

+507
-2
lines changed

6 files changed

+507
-2
lines changed

samtranslator/plugins/api/implicit_api_plugin.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ def _add_tags_to_implicit_api_if_necessary(
109109
implicit_api_resource = template.get(self.IMPLICIT_API_LOGICAL_ID)
110110
globals_var = template.get_globals().get(SamResourceType(resource.type).name, {})
111111
should_propagate_tags = resource.properties.get("PropagateTags") or globals_var.get("PropagateTags")
112+
tags_properties = resource.properties.get("Tags") or globals_var.get("Tags")
112113

113-
if implicit_api_resource and resource.properties.get("Tags") and should_propagate_tags:
114+
if implicit_api_resource and tags_properties and should_propagate_tags:
114115
# This makes an assumption that the SAM resource has 'Tags' property and is a dictionary.
115-
implicit_api_resource.properties.setdefault("Tags", {}).update(resource.properties["Tags"])
116+
implicit_api_resource.properties.setdefault("Tags", {}).update(tags_properties)
116117
implicit_api_resource.properties["PropagateTags"] = True
117118

118119
@cw_timer(prefix="Plugin-ImplicitApi")

tests/plugins/api/test_implicit_api_plugin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ def test_must_verify_expected_keys_exist(self):
369369
api_events = {"Api1": {"Type": "Api", "Properties": {"Path": "/", "Methid": "POST"}}}
370370

371371
template = Mock()
372+
template.get_globals.return_value = {}
372373
function_events_mock = Mock()
373374
function = SamResource({"Type": SamResourceType.Function.value, "Properties": {"Events": function_events_mock}})
374375
function_events_mock.update = Mock()
@@ -380,6 +381,7 @@ def test_must_verify_method_is_string(self):
380381
api_events = {"Api1": {"Type": "Api", "Properties": {"Path": "/", "Method": ["POST"]}}}
381382

382383
template = Mock()
384+
template.get_globals.return_value = {}
383385
function_events_mock = Mock()
384386
function = SamResource({"Type": SamResourceType.Function.value, "Properties": {"Events": function_events_mock}})
385387
function_events_mock.update = Mock()
@@ -411,6 +413,7 @@ def test_must_verify_path_is_string(self):
411413
api_events = {"Api1": {"Type": "Api", "Properties": {"Path": ["/"], "Method": "POST"}}}
412414

413415
template = Mock()
416+
template.get_globals.return_value = {}
414417
function_events_mock = Mock()
415418
function = SamResource({"Type": SamResourceType.Function.value, "Properties": {"Events": function_events_mock}})
416419
function_events_mock.update = Mock()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Globals:
2+
Function:
3+
Tags:
4+
test: 'yes'
5+
6+
Resources:
7+
ApiFunction: # Adds a GET api endpoint at "/" to the ApiGatewayApi via an Api event
8+
Type: AWS::Serverless::Function
9+
Properties:
10+
PropagateTags: true
11+
Events:
12+
ApiEvent:
13+
Type: Api
14+
Properties:
15+
Path: /
16+
Method: get
17+
RequestParameters:
18+
- method.request.header.Authorization
19+
- method.request.querystring.keyword:
20+
Required: true
21+
Caching: false
22+
Runtime: python3.7
23+
Handler: index.handler
24+
InlineCode: |-
25+
def handler(event, context):
26+
return {'body': 'Hello World!', 'statusCode': 200}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
{
2+
"Resources": {
3+
"ApiFunction": {
4+
"Properties": {
5+
"Code": {
6+
"ZipFile": "def handler(event, context):\n return {'body': 'Hello World!', 'statusCode': 200}"
7+
},
8+
"Handler": "index.handler",
9+
"Role": {
10+
"Fn::GetAtt": [
11+
"ApiFunctionRole",
12+
"Arn"
13+
]
14+
},
15+
"Runtime": "python3.7",
16+
"Tags": [
17+
{
18+
"Key": "test",
19+
"Value": "yes"
20+
}
21+
]
22+
},
23+
"Type": "AWS::Lambda::Function"
24+
},
25+
"ApiFunctionApiEventPermissionProd": {
26+
"Properties": {
27+
"Action": "lambda:InvokeFunction",
28+
"FunctionName": {
29+
"Ref": "ApiFunction"
30+
},
31+
"Principal": "apigateway.amazonaws.com",
32+
"SourceArn": {
33+
"Fn::Sub": [
34+
"arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/",
35+
{
36+
"__ApiId__": {
37+
"Ref": "ServerlessRestApi"
38+
},
39+
"__Stage__": "*"
40+
}
41+
]
42+
}
43+
},
44+
"Type": "AWS::Lambda::Permission"
45+
},
46+
"ApiFunctionRole": {
47+
"Properties": {
48+
"AssumeRolePolicyDocument": {
49+
"Statement": [
50+
{
51+
"Action": [
52+
"sts:AssumeRole"
53+
],
54+
"Effect": "Allow",
55+
"Principal": {
56+
"Service": [
57+
"lambda.amazonaws.com"
58+
]
59+
}
60+
}
61+
],
62+
"Version": "2012-10-17"
63+
},
64+
"ManagedPolicyArns": [
65+
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
66+
],
67+
"Tags": [
68+
{
69+
"Key": "test",
70+
"Value": "yes"
71+
}
72+
]
73+
},
74+
"Type": "AWS::IAM::Role"
75+
},
76+
"ServerlessRestApi": {
77+
"Properties": {
78+
"Body": {
79+
"info": {
80+
"title": {
81+
"Ref": "AWS::StackName"
82+
},
83+
"version": "1.0"
84+
},
85+
"paths": {
86+
"/": {
87+
"get": {
88+
"parameters": [
89+
{
90+
"in": "header",
91+
"name": "Authorization",
92+
"required": false,
93+
"type": "string"
94+
},
95+
{
96+
"in": "query",
97+
"name": "keyword",
98+
"required": true,
99+
"type": "string"
100+
}
101+
],
102+
"responses": {},
103+
"x-amazon-apigateway-integration": {
104+
"httpMethod": "POST",
105+
"type": "aws_proxy",
106+
"uri": {
107+
"Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations"
108+
}
109+
}
110+
}
111+
}
112+
},
113+
"swagger": "2.0"
114+
},
115+
"EndpointConfiguration": {
116+
"Types": [
117+
"REGIONAL"
118+
]
119+
},
120+
"Parameters": {
121+
"endpointConfigurationTypes": "REGIONAL"
122+
},
123+
"Tags": [
124+
{
125+
"Key": "test",
126+
"Value": "yes"
127+
}
128+
]
129+
},
130+
"Type": "AWS::ApiGateway::RestApi"
131+
},
132+
"ServerlessRestApiDeployment4036e5c19a": {
133+
"Properties": {
134+
"Description": "RestApi deployment id: 4036e5c19a6892f11f6cc916e1588a5723066abf",
135+
"RestApiId": {
136+
"Ref": "ServerlessRestApi"
137+
},
138+
"StageName": "Stage"
139+
},
140+
"Type": "AWS::ApiGateway::Deployment"
141+
},
142+
"ServerlessRestApiProdStage": {
143+
"Properties": {
144+
"DeploymentId": {
145+
"Ref": "ServerlessRestApiDeployment4036e5c19a"
146+
},
147+
"RestApiId": {
148+
"Ref": "ServerlessRestApi"
149+
},
150+
"StageName": "Prod",
151+
"Tags": [
152+
{
153+
"Key": "test",
154+
"Value": "yes"
155+
}
156+
]
157+
},
158+
"Type": "AWS::ApiGateway::Stage"
159+
}
160+
}
161+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
{
2+
"Resources": {
3+
"ApiFunction": {
4+
"Properties": {
5+
"Code": {
6+
"ZipFile": "def handler(event, context):\n return {'body': 'Hello World!', 'statusCode': 200}"
7+
},
8+
"Handler": "index.handler",
9+
"Role": {
10+
"Fn::GetAtt": [
11+
"ApiFunctionRole",
12+
"Arn"
13+
]
14+
},
15+
"Runtime": "python3.7",
16+
"Tags": [
17+
{
18+
"Key": "test",
19+
"Value": "yes"
20+
}
21+
]
22+
},
23+
"Type": "AWS::Lambda::Function"
24+
},
25+
"ApiFunctionApiEventPermissionProd": {
26+
"Properties": {
27+
"Action": "lambda:InvokeFunction",
28+
"FunctionName": {
29+
"Ref": "ApiFunction"
30+
},
31+
"Principal": "apigateway.amazonaws.com",
32+
"SourceArn": {
33+
"Fn::Sub": [
34+
"arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/",
35+
{
36+
"__ApiId__": {
37+
"Ref": "ServerlessRestApi"
38+
},
39+
"__Stage__": "*"
40+
}
41+
]
42+
}
43+
},
44+
"Type": "AWS::Lambda::Permission"
45+
},
46+
"ApiFunctionRole": {
47+
"Properties": {
48+
"AssumeRolePolicyDocument": {
49+
"Statement": [
50+
{
51+
"Action": [
52+
"sts:AssumeRole"
53+
],
54+
"Effect": "Allow",
55+
"Principal": {
56+
"Service": [
57+
"lambda.amazonaws.com"
58+
]
59+
}
60+
}
61+
],
62+
"Version": "2012-10-17"
63+
},
64+
"ManagedPolicyArns": [
65+
"arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
66+
],
67+
"Tags": [
68+
{
69+
"Key": "test",
70+
"Value": "yes"
71+
}
72+
]
73+
},
74+
"Type": "AWS::IAM::Role"
75+
},
76+
"ServerlessRestApi": {
77+
"Properties": {
78+
"Body": {
79+
"info": {
80+
"title": {
81+
"Ref": "AWS::StackName"
82+
},
83+
"version": "1.0"
84+
},
85+
"paths": {
86+
"/": {
87+
"get": {
88+
"parameters": [
89+
{
90+
"in": "header",
91+
"name": "Authorization",
92+
"required": false,
93+
"type": "string"
94+
},
95+
{
96+
"in": "query",
97+
"name": "keyword",
98+
"required": true,
99+
"type": "string"
100+
}
101+
],
102+
"responses": {},
103+
"x-amazon-apigateway-integration": {
104+
"httpMethod": "POST",
105+
"type": "aws_proxy",
106+
"uri": {
107+
"Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations"
108+
}
109+
}
110+
}
111+
}
112+
},
113+
"swagger": "2.0"
114+
},
115+
"EndpointConfiguration": {
116+
"Types": [
117+
"REGIONAL"
118+
]
119+
},
120+
"Parameters": {
121+
"endpointConfigurationTypes": "REGIONAL"
122+
},
123+
"Tags": [
124+
{
125+
"Key": "test",
126+
"Value": "yes"
127+
}
128+
]
129+
},
130+
"Type": "AWS::ApiGateway::RestApi"
131+
},
132+
"ServerlessRestApiDeployment06c7f65191": {
133+
"Properties": {
134+
"Description": "RestApi deployment id: 06c7f651916afb666c61d5700ef27473645d640a",
135+
"RestApiId": {
136+
"Ref": "ServerlessRestApi"
137+
},
138+
"StageName": "Stage"
139+
},
140+
"Type": "AWS::ApiGateway::Deployment"
141+
},
142+
"ServerlessRestApiProdStage": {
143+
"Properties": {
144+
"DeploymentId": {
145+
"Ref": "ServerlessRestApiDeployment06c7f65191"
146+
},
147+
"RestApiId": {
148+
"Ref": "ServerlessRestApi"
149+
},
150+
"StageName": "Prod",
151+
"Tags": [
152+
{
153+
"Key": "test",
154+
"Value": "yes"
155+
}
156+
]
157+
},
158+
"Type": "AWS::ApiGateway::Stage"
159+
}
160+
}
161+
}

0 commit comments

Comments
 (0)