Skip to content

Commit 0ca6e6f

Browse files
seshubawsSmoothex
authored andcommitted
Add proptags for codedeploy resources (aws#3885)
1 parent 256436e commit 0ca6e6f

File tree

9 files changed

+130
-20
lines changed

9 files changed

+130
-20
lines changed

samtranslator/model/preferences/deployment_preference.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
:param enabled: Whether this deployment preference is enabled (true by default)
2323
:param trigger_configurations: Information about triggers associated with the deployment group. Duplicates are
2424
not allowed.
25+
:param tags: Tags to propagate to CodeDeploy resources when propagate_tags is enabled
26+
:param propagate_tags: Whether to propagate tags to CodeDeploy resources
2527
"""
2628
DeploymentPreferenceTuple = namedtuple(
2729
"DeploymentPreferenceTuple",
@@ -34,6 +36,8 @@
3436
"role",
3537
"trigger_configurations",
3638
"condition",
39+
"tags",
40+
"propagate_tags",
3741
],
3842
)
3943

@@ -46,18 +50,20 @@ class DeploymentPreference(DeploymentPreferenceTuple):
4650
"""
4751

4852
@classmethod
49-
def from_dict(cls, logical_id, deployment_preference_dict, condition=None): # type: ignore[no-untyped-def]
53+
def from_dict(cls, logical_id, deployment_preference_dict, condition=None, tags=None, propagate_tags=False): # type: ignore[no-untyped-def]
5054
"""
5155
:param logical_id: the logical_id of the resource that owns this deployment preference
5256
:param deployment_preference_dict: the dict object taken from the SAM template
5357
:param condition: condition on this deployment preference
58+
:param tags: tags from the SAM resource to propagate to CodeDeploy resources
59+
:param propagate_tags: whether to propagate tags to CodeDeploy resources
5460
:return:
5561
"""
5662
enabled = deployment_preference_dict.get("Enabled", True)
5763
enabled = False if enabled in ["false", "False"] else enabled
5864

5965
if not enabled:
60-
return DeploymentPreference(None, None, None, None, False, None, None, None)
66+
return DeploymentPreference(None, None, None, None, False, None, None, None, None, None)
6167

6268
if "Type" not in deployment_preference_dict:
6369
raise InvalidResourceException(logical_id, "'DeploymentPreference' is missing required Property 'Type'")
@@ -85,4 +91,6 @@ def from_dict(cls, logical_id, deployment_preference_dict, condition=None): # t
8591
role,
8692
trigger_configurations,
8793
condition if passthrough_condition else None,
94+
tags if propagate_tags and tags else None,
95+
propagate_tags,
8896
)

samtranslator/model/preferences/deployment_preference_collection.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
ref,
1515
validate_intrinsic_if_items,
1616
)
17+
from samtranslator.model.tags.resource_tagging import get_tag_list
1718
from samtranslator.model.update_policy import UpdatePolicy
1819
from samtranslator.translator.arn_generator import ArnGenerator
1920

@@ -52,20 +53,29 @@ def __init__(self) -> None:
5253
"""
5354
self._resource_preferences: Dict[str, Any] = {}
5455

55-
def add(self, logical_id: str, deployment_preference_dict: Dict[str, Any], condition: Optional[str] = None) -> None:
56+
def add(
57+
self,
58+
logical_id: str,
59+
deployment_preference_dict: Dict[str, Any],
60+
condition: Optional[str] = None,
61+
tags: Optional[Dict[str, Any]] = None,
62+
propagate_tags: Optional[bool] = False,
63+
) -> None:
5664
"""
5765
Add this deployment preference to the collection
5866
5967
:raise ValueError if an existing logical id already exists in the _resource_preferences
6068
:param logical_id: logical id of the resource where this deployment preference applies
6169
:param deployment_preference_dict: the input SAM template deployment preference mapping
6270
:param condition: the condition (if it exists) on the serverless function
71+
:param tags: tags from the SAM resource to propagate to CodeDeploy resources
72+
:param propagate_tags: whether to propagate tags to CodeDeploy resources
6373
"""
6474
if logical_id in self._resource_preferences:
6575
raise ValueError(f"logical_id {logical_id} previously added to this deployment_preference_collection")
6676

6777
self._resource_preferences[logical_id] = DeploymentPreference.from_dict( # type: ignore[no-untyped-call]
68-
logical_id, deployment_preference_dict, condition
78+
logical_id, deployment_preference_dict, condition, tags, propagate_tags
6979
)
7080

7181
def get(self, logical_id: str) -> DeploymentPreference:
@@ -127,6 +137,13 @@ def enabled_logical_ids(self) -> List[str]:
127137
def get_codedeploy_application(self) -> CodeDeployApplication:
128138
codedeploy_application_resource = CodeDeployApplication(CODEDEPLOY_APPLICATION_LOGICAL_ID)
129139
codedeploy_application_resource.ComputePlatform = "Lambda"
140+
141+
merged_tags: Dict[str, Any] = {}
142+
for preference in self._resource_preferences.values():
143+
if preference.enabled and preference.propagate_tags and preference.tags:
144+
merged_tags.update(preference.tags)
145+
if merged_tags:
146+
codedeploy_application_resource.Tags = get_tag_list(merged_tags)
130147
if self.needs_resource_condition():
131148
conditions = self.get_all_deployment_conditions()
132149
condition_name = CODE_DEPLOY_CONDITION_NAME
@@ -165,6 +182,14 @@ def get_codedeploy_iam_role(self) -> IAMRole:
165182
if len(conditions) <= 1:
166183
condition_name = conditions.pop()
167184
iam_role.set_resource_attribute("Condition", condition_name)
185+
186+
merged_tags: Dict[str, Any] = {}
187+
for preference in self._resource_preferences.values():
188+
if preference.enabled and preference.propagate_tags and preference.tags:
189+
merged_tags.update(preference.tags)
190+
if merged_tags:
191+
iam_role.Tags = get_tag_list(merged_tags)
192+
168193
return iam_role
169194

170195
def deployment_group(self, function_logical_id: str) -> CodeDeployDeploymentGroup:
@@ -201,6 +226,9 @@ def deployment_group(self, function_logical_id: str) -> CodeDeployDeploymentGrou
201226
if deployment_preference.trigger_configurations:
202227
deployment_group.TriggerConfigurations = deployment_preference.trigger_configurations
203228

229+
if deployment_preference.tags:
230+
deployment_group.Tags = get_tag_list(deployment_preference.tags)
231+
204232
if deployment_preference.condition:
205233
deployment_group.set_resource_attribute("Condition", deployment_preference.condition)
206234

samtranslator/model/sam_resources.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""SAM macro definitions"""
1+
"""SAM macro definitions"""
22

33
import copy
44
import re
@@ -1308,6 +1308,8 @@ def _validate_deployment_preference_and_add_update_policy( # noqa: PLR0913
13081308
self.logical_id,
13091309
self.DeploymentPreference,
13101310
passthrough_resource_attributes.get("Condition"),
1311+
self.Tags,
1312+
self.PropagateTags,
13111313
)
13121314

13131315
if deployment_preference_collection.get(self.logical_id).enabled:

tests/translator/input/function_with_propagate_tags_and_no_tags.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Resources:
66
exports.handler = async () => ‘Hello World!'
77
Handler: index.handler
88
Runtime: nodejs18.x
9-
# PropagateTags: True
9+
PropagateTags: true
1010
AutoPublishAlias: Live
1111
Events:
1212
CWEvent:

tests/translator/model/preferences/test_deployment_preference.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def test_from_dict_with_intrinsic_function_type(self):
2929
self.role,
3030
self.trigger_configurations,
3131
None,
32+
None,
33+
False,
3234
)
3335

3436
deployment_preference_yaml_dict = dict()
@@ -56,6 +58,8 @@ def test_from_dict(self):
5658
self.role,
5759
self.trigger_configurations,
5860
None,
61+
None,
62+
False,
5963
)
6064

6165
deployment_preference_yaml_dict = dict()
@@ -83,6 +87,8 @@ def test_from_dict_with_passthrough_condition(self):
8387
self.role,
8488
self.trigger_configurations,
8589
self.condition,
90+
None,
91+
False,
8692
)
8793

8894
deployment_preference_yaml_dict = dict()
@@ -102,7 +108,9 @@ def test_from_dict_with_passthrough_condition(self):
102108
self.assertEqual(expected_deployment_preference, deployment_preference_from_yaml_dict)
103109

104110
def test_from_dict_with_disabled_preference_does_not_require_other_parameters(self):
105-
expected_deployment_preference = DeploymentPreference(None, None, None, None, False, None, None, None)
111+
expected_deployment_preference = DeploymentPreference(
112+
None, None, None, None, False, None, None, None, None, None
113+
)
106114

107115
deployment_preference_yaml_dict = dict()
108116
deployment_preference_yaml_dict["Enabled"] = False
@@ -113,7 +121,9 @@ def test_from_dict_with_disabled_preference_does_not_require_other_parameters(se
113121
self.assertEqual(expected_deployment_preference, deployment_preference_from_yaml_dict)
114122

115123
def test_from_dict_with_string_disabled_preference_does_not_require_other_parameters(self):
116-
expected_deployment_preference = DeploymentPreference(None, None, None, None, False, None, None, None)
124+
expected_deployment_preference = DeploymentPreference(
125+
None, None, None, None, False, None, None, None, None, None
126+
)
117127

118128
deployment_preference_yaml_dict = dict()
119129
deployment_preference_yaml_dict["Enabled"] = "False"
@@ -124,7 +134,9 @@ def test_from_dict_with_string_disabled_preference_does_not_require_other_parame
124134
self.assertEqual(expected_deployment_preference, deployment_preference_from_yaml_dict)
125135

126136
def test_from_dict_with_lowercase_string_disabled_preference_does_not_require_other_parameters(self):
127-
expected_deployment_preference = DeploymentPreference(None, None, None, None, False, None, None, None)
137+
expected_deployment_preference = DeploymentPreference(
138+
None, None, None, None, False, None, None, None, None, None
139+
)
128140

129141
deployment_preference_yaml_dict = dict()
130142
deployment_preference_yaml_dict["Enabled"] = "false"

tests/translator/output/aws-cn/function_with_events_and_propagate_tags.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,17 @@
311311
"DeploymentRole",
312312
"Arn"
313313
]
314-
}
314+
},
315+
"Tags": [
316+
{
317+
"Key": "Key1",
318+
"Value": "Value1"
319+
},
320+
{
321+
"Key": "Key2",
322+
"Value": "Value2"
323+
}
324+
]
315325
},
316326
"Type": "AWS::CodeDeploy::DeploymentGroup"
317327
},
@@ -520,7 +530,17 @@
520530
},
521531
"ServerlessDeploymentApplication": {
522532
"Properties": {
523-
"ComputePlatform": "Lambda"
533+
"ComputePlatform": "Lambda",
534+
"Tags": [
535+
{
536+
"Key": "Key1",
537+
"Value": "Value1"
538+
},
539+
{
540+
"Key": "Key2",
541+
"Value": "Value2"
542+
}
543+
]
524544
},
525545
"Type": "AWS::CodeDeploy::Application"
526546
},

tests/translator/output/aws-us-gov/function_with_events_and_propagate_tags.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,17 @@
311311
"DeploymentRole",
312312
"Arn"
313313
]
314-
}
314+
},
315+
"Tags": [
316+
{
317+
"Key": "Key1",
318+
"Value": "Value1"
319+
},
320+
{
321+
"Key": "Key2",
322+
"Value": "Value2"
323+
}
324+
]
315325
},
316326
"Type": "AWS::CodeDeploy::DeploymentGroup"
317327
},
@@ -520,7 +530,17 @@
520530
},
521531
"ServerlessDeploymentApplication": {
522532
"Properties": {
523-
"ComputePlatform": "Lambda"
533+
"ComputePlatform": "Lambda",
534+
"Tags": [
535+
{
536+
"Key": "Key1",
537+
"Value": "Value1"
538+
},
539+
{
540+
"Key": "Key2",
541+
"Value": "Value2"
542+
}
543+
]
524544
},
525545
"Type": "AWS::CodeDeploy::Application"
526546
},

tests/translator/output/function_with_events_and_propagate_tags.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,17 @@
311311
"DeploymentRole",
312312
"Arn"
313313
]
314-
}
314+
},
315+
"Tags": [
316+
{
317+
"Key": "Key1",
318+
"Value": "Value1"
319+
},
320+
{
321+
"Key": "Key2",
322+
"Value": "Value2"
323+
}
324+
]
315325
},
316326
"Type": "AWS::CodeDeploy::DeploymentGroup"
317327
},
@@ -520,7 +530,17 @@
520530
},
521531
"ServerlessDeploymentApplication": {
522532
"Properties": {
523-
"ComputePlatform": "Lambda"
533+
"ComputePlatform": "Lambda",
534+
"Tags": [
535+
{
536+
"Key": "Key1",
537+
"Value": "Value1"
538+
},
539+
{
540+
"Key": "Key2",
541+
"Value": "Value2"
542+
}
543+
]
524544
},
525545
"Type": "AWS::CodeDeploy::Application"
526546
},

tests/translator/test_function_resources.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def test_sam_function_with_deployment_preference(self, get_resolved_alias_name_m
149149

150150
deployment_preference_collection.update_policy.assert_called_once_with(self.sam_func.logical_id)
151151
deployment_preference_collection.add.assert_called_once_with(
152-
self.sam_func.logical_id, deploy_preference_dict, None
152+
self.sam_func.logical_id, deploy_preference_dict, None, None, None
153153
)
154154

155155
aliases = [r.to_dict() for r in resources if r.resource_type == LambdaAlias.resource_type]
@@ -230,7 +230,7 @@ def test_sam_function_with_disabled_deployment_preference_does_not_add_update_po
230230

231231
resources = sam_func.to_cloudformation(**kwargs)
232232

233-
preference_collection.add.assert_called_once_with(sam_func.logical_id, deploy_preference_dict, None)
233+
preference_collection.add.assert_called_once_with(sam_func.logical_id, deploy_preference_dict, None, None, None)
234234
preference_collection.get.assert_called_once_with(sam_func.logical_id)
235235
self.intrinsics_resolver_mock.resolve_parameter_refs.assert_has_calls([call(enabled), call(None)])
236236
aliases = [r.to_dict() for r in resources if r.resource_type == LambdaAlias.resource_type]
@@ -330,7 +330,7 @@ def test_sam_function_with_deployment_preference_intrinsic_ref_enabled_boolean_p
330330

331331
deployment_preference_collection.update_policy.assert_called_once_with(self.sam_func.logical_id)
332332
deployment_preference_collection.add.assert_called_once_with(
333-
self.sam_func.logical_id, deploy_preference_dict, None
333+
self.sam_func.logical_id, deploy_preference_dict, None, None, None
334334
)
335335
self.intrinsics_resolver_mock.resolve_parameter_refs.assert_any_call(enabled)
336336

@@ -451,7 +451,7 @@ def test_sam_function_with_deployment_preference_passthrough_condition_through_p
451451

452452
deployment_preference_collection.update_policy.assert_called_once_with(self.sam_func.logical_id)
453453
deployment_preference_collection.add.assert_called_once_with(
454-
self.sam_func.logical_id, deploy_preference_dict, "Condition1"
454+
self.sam_func.logical_id, deploy_preference_dict, "Condition1", None, None
455455
)
456456

457457
aliases = [r.to_dict() for r in resources if r.resource_type == LambdaAlias.resource_type]
@@ -502,7 +502,7 @@ def test_sam_function_with_deployment_preference_passthrough_condition_through_f
502502

503503
deployment_preference_collection.update_policy.assert_called_once_with(self.sam_func.logical_id)
504504
deployment_preference_collection.add.assert_called_once_with(
505-
self.sam_func.logical_id, deploy_preference_dict, "Condition1"
505+
self.sam_func.logical_id, deploy_preference_dict, "Condition1", None, None
506506
)
507507

508508
aliases = [r.to_dict() for r in resources if r.resource_type == LambdaAlias.resource_type]

0 commit comments

Comments
 (0)