Skip to content

Commit

Permalink
Do not purge 'aws:*' tags (#825)
Browse files Browse the repository at this point in the history
Do not purge 'aws:*' tags

SUMMARY
fixes: #817
According to the AWS documentation

System created tags that begin with aws: are reserved for AWS use ... You can't edit or delete a tag that begins with the aws: prefix.

The most common use case here is AWS CloudFormation, which adds a "aws:cloudformation:stack-name" tag.  Since we can't manage these tags at all we should ignore them for the purposes of 'purging'.  If someone explicitly adds the tag, then it's reasonable to let the APIs throw an error at them, but otherwise do the best we can.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME
plugins/module_utils/tagging.py
ADDITIONAL INFORMATION

Reviewed-by: Alina Buzachis <None>
Reviewed-by: Joseph Torcasso <None>
  • Loading branch information
tremble authored May 27, 2022
1 parent 9639325 commit 8c4e2d5
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/817-skip_purge_aws.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
breaking_changes:
- Tags beginning with ``aws:`` will not be removed when purging tags, these tags are reserved by Amazon and may not be updated or deleted (https://github.com/ansible-collections/amazon.aws/issues/817).
10 changes: 8 additions & 2 deletions plugins/module_utils/tagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,14 @@ def compare_aws_tags(current_tags_dict, new_tags_dict, purge_tags=True):
tag_key_value_pairs_to_set = {}
tag_keys_to_unset = []

for key in current_tags_dict.keys():
if key not in new_tags_dict and purge_tags:
if purge_tags:
for key in current_tags_dict.keys():
if key in new_tags_dict:
continue
# Amazon have reserved 'aws:*' tags, we should avoid purging them as
# this probably isn't what people want to do...
if key.startswith('aws:'):
continue
tag_keys_to_unset.append(key)

for key in set(new_tags_dict.keys()) - set(tag_keys_to_unset):
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/targets/ec2_instance/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@
- hosts: all
gather_facts: no
strategy: free
serial: 6
serial: 7
roles:
- ec2_instance
34 changes: 34 additions & 0 deletions tests/unit/module_utils/test_tagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def setUp(self):

self.tag_minimal_dict = {'mykey': 'myvalue'}

self.tag_aws_dict = {'aws:cloudformation:stack-name': 'ExampleStack'}
self.tag_aws_changed = {'aws:cloudformation:stack-name': 'AnotherStack'}

# ========================================================
# tagging.ansible_dict_to_boto3_tag_list
# ========================================================
Expand Down Expand Up @@ -139,6 +142,37 @@ def test_compare_aws_tags_complex_update(self):
self.assertEqual(new_keys, keys_to_set)
self.assertEqual(['Normal case'], keys_to_unset)

def test_compare_aws_tags_aws(self):
starting_tags = dict(self.tag_aws_dict)
desired_tags = dict(self.tag_minimal_dict)
tags_to_set, tags_to_unset = compare_aws_tags(starting_tags, desired_tags, purge_tags=True)
self.assertEqual(desired_tags, tags_to_set)
self.assertEqual([], tags_to_unset)
# If someone explicitly passes a changed 'aws:' key the APIs will probably
# throw an error, but this is their responsibility.
desired_tags.update(self.tag_aws_changed)
tags_to_set, tags_to_unset = compare_aws_tags(starting_tags, desired_tags, purge_tags=True)
self.assertEqual(desired_tags, tags_to_set)
self.assertEqual([], tags_to_unset)

def test_compare_aws_tags_aws_complex(self):
old_dict = dict(self.tag_example_dict)
old_dict.update(self.tag_aws_dict)
# Adds 'Me too!', Changes 'UpperCamel' and removes 'Normal case'
new_dict = dict(self.tag_example_dict)
new_keys = {'UpperCamel': 'anotherCamelValue', 'Me too!': 'Contributing'}
new_dict.update(new_keys)
del new_dict['Normal case']
keys_to_set, keys_to_unset = compare_aws_tags(old_dict, new_dict)
self.assertEqual(new_keys, keys_to_set)
self.assertEqual(['Normal case'], keys_to_unset)
keys_to_set, keys_to_unset = compare_aws_tags(old_dict, new_dict, purge_tags=False)
self.assertEqual(new_keys, keys_to_set)
self.assertEqual([], keys_to_unset)
keys_to_set, keys_to_unset = compare_aws_tags(old_dict, new_dict, purge_tags=True)
self.assertEqual(new_keys, keys_to_set)
self.assertEqual(['Normal case'], keys_to_unset)

# ========================================================
# tagging.boto3_tag_specifications
# ========================================================
Expand Down

0 comments on commit 8c4e2d5

Please sign in to comment.