Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sns_topic - Add tags and purge_tags options #972

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
2 changes: 2 additions & 0 deletions changelogs/fragments/972-sns_topic-add_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- sns_topic - add support for ``tags`` and ``purge_tags`` (https://github.com/ansible-collections/community.aws/pull/972).
45 changes: 44 additions & 1 deletion plugins/module_utils/sns.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags


@AWSRetry.jittered_backoff()
Expand Down Expand Up @@ -87,6 +91,16 @@ def canonicalize_endpoint(protocol, endpoint):
return endpoint


def get_tags(client, module, topic_arn):
try:
return boto3_tag_list_to_ansible_dict(client.list_tags_for_resource(ResourceArn=topic_arn)['Tags'])
except is_boto3_error_code('AuthorizationError'):
module.warn("Permission denied accessing tags")
return {}
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
tremble marked this conversation as resolved.
Show resolved Hide resolved
module.fail_json_aws(e, msg="Couldn't obtain topic tags")


def get_info(connection, module, topic_arn):
name = module.params.get('name')
topic_type = module.params.get('topic_type')
Expand Down Expand Up @@ -121,5 +135,34 @@ def get_info(connection, module, topic_arn):
info.update(camel_dict_to_snake_dict(connection.get_topic_attributes(TopicArn=topic_arn)['Attributes']))
info['delivery_policy'] = info.pop('effective_delivery_policy')
info['subscriptions'] = [camel_dict_to_snake_dict(sub) for sub in list_topic_subscriptions(connection, module, topic_arn)]

info["tags"] = get_tags(connection, module, topic_arn)
return info


def update_tags(client, module, topic_arn):

if module.params.get('tags') is None:
return False

existing_tags = get_tags(client, module, topic_arn)
to_update, to_delete = compare_aws_tags(existing_tags, module.params['tags'], module.params['purge_tags'])

if not bool(to_delete or to_update):
return False

if module.check_mode:
return True

if to_update:
try:
client.tag_resource(ResourceArn=topic_arn,
Tags=ansible_dict_to_boto3_tag_list(to_update))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't add tags to topic")
if to_delete:
try:
client.untag_resource(ResourceArn=topic_arn, TagKeys=to_delete)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't remove tags from topic")

return True
30 changes: 24 additions & 6 deletions plugins/modules/sns_topic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
short_description: Manages AWS SNS topics and subscriptions
version_added: 1.0.0
description:
- The M(community.aws.sns_topic) module allows you to create, delete, and manage subscriptions for AWS SNS topics.
- As of 2.6, this module can be use to subscribe and unsubscribe to topics outside of your AWS account.
- The M(community.aws.sns_topic) module allows you to create, delete, and manage subscriptions for AWS SNS topics.
author:
- "Joel Thompson (@joelthompson)"
- "Fernando Jose Pando (@nand0p)"
Expand Down Expand Up @@ -149,10 +148,13 @@
Blame Amazon."
default: true
type: bool
notes:
- Support for I(tags) and I(purge_tags) was added in release 5.3.0.
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
- amazon.aws.boto3
- amazon.aws.common.modules
- amazon.aws.region.modules
- amazon.aws.tags.modules
- amazon.aws.boto3
'''

EXAMPLES = r"""
Expand Down Expand Up @@ -328,12 +330,14 @@
from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
from ansible_collections.community.aws.plugins.module_utils.sns import list_topics
from ansible_collections.community.aws.plugins.module_utils.sns import topic_arn_lookup
from ansible_collections.community.aws.plugins.module_utils.sns import compare_delivery_policies
from ansible_collections.community.aws.plugins.module_utils.sns import list_topic_subscriptions
from ansible_collections.community.aws.plugins.module_utils.sns import canonicalize_endpoint
from ansible_collections.community.aws.plugins.module_utils.sns import get_info
from ansible_collections.community.aws.plugins.module_utils.sns import update_tags


class SnsTopicManager(object):
Expand All @@ -349,6 +353,8 @@ def __init__(self,
delivery_policy,
subscriptions,
purge_subscriptions,
tags,
purge_tags,
check_mode):

self.connection = module.client('sns')
Expand All @@ -371,6 +377,8 @@ def __init__(self,
self.topic_deleted = False
self.topic_arn = None
self.attributes_set = []
self.tags = tags
self.purge_tags = purge_tags

def _create_topic(self):
attributes = {}
Expand All @@ -383,6 +391,9 @@ def _create_topic(self):
if not self.name.endswith('.fifo'):
self.name = self.name + '.fifo'

if self.tags:
tags = ansible_dict_to_boto3_tag_list(self.tags)

if not self.check_mode:
try:
response = self.connection.create_topic(Name=self.name,
Expand Down Expand Up @@ -542,12 +553,13 @@ def ensure_ok(self):
elif self.display_name or self.policy or self.delivery_policy:
self.module.fail_json(msg="Cannot set display name, policy or delivery policy for SNS topics not owned by this account")
changed |= self._set_topic_subs()

self._init_desired_subscription_attributes()
if self.topic_arn in list_topics(self.connection, self.module):
changed |= self._set_topic_subs_attributes()
elif any(self.desired_subscription_attributes.values()):
self.module.fail_json(msg="Cannot set subscription attributes for SNS topics not owned by this account")
# Check tagging
changed |= update_tags(self.connection, self.module, self.topic_arn)
tremble marked this conversation as resolved.
Show resolved Hide resolved

return changed

Expand Down Expand Up @@ -600,6 +612,8 @@ def main():
delivery_policy=dict(type='dict', options=delivery_args),
subscriptions=dict(default=[], type='list', elements='dict'),
purge_subscriptions=dict(type='bool', default=True),
tags=dict(type='dict', aliases=['resource_tags']),
purge_tags=dict(type='bool', default=True),
)

module = AnsibleAWSModule(argument_spec=argument_spec,
Expand All @@ -614,6 +628,8 @@ def main():
subscriptions = module.params.get('subscriptions')
purge_subscriptions = module.params.get('purge_subscriptions')
check_mode = module.check_mode
tags = module.params.get('tags')
purge_tags = module.params.get('purge_tags')

sns_topic = SnsTopicManager(module,
name,
Expand All @@ -624,6 +640,8 @@ def main():
delivery_policy,
subscriptions,
purge_subscriptions,
tags,
purge_tags,
check_mode)

if state == 'present':
Expand Down
170 changes: 165 additions & 5 deletions tests/integration/targets/sns_topic/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
create_instance_profile: false
managed_policies:
- 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess'
wait: True
register: iam_role

- name: pause if role was created
pause:
seconds: 10
when: iam_role is changed

- name: list all the topics (check_mode)
sns_topic_info:
check_mode: true
Expand Down Expand Up @@ -428,6 +424,170 @@
- third_party_deletion is failed
- third_party_topic.sns_topic.subscriptions|length == third_party_deletion_facts.sns_topic.subscriptions|length

# Test tags
- name: create standard SNS topic
sns_topic:
name: '{{ sns_topic_topic_name }}'
display_name: My topic name
register: sns_topic_create

- name: assert that creation worked
assert:
that:
- sns_topic_create.changed

- name: set sns_arn fact
set_fact:
sns_arn: '{{ sns_topic_create.sns_arn }}'

- name: Add tags to topic - CHECK_MODE
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_one: '{{ tiny_prefix }} One'
"Tag Two": 'two {{ tiny_prefix }}'
check_mode: true
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Add tags to topic
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_one: '{{ tiny_prefix }} One'
"Tag Two": 'two {{ tiny_prefix }}'
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Add tags to topic to verify idempotency - CHECK_MODE
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_one: '{{ tiny_prefix }} One'
"Tag Two": 'two {{ tiny_prefix }}'
check_mode: true
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is not changed

- name: Add tags to topic to verify idempotency
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_one: '{{ tiny_prefix }} One'
"Tag Two": 'two {{ tiny_prefix }}'
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is not changed

- name: Update (add/remove) tags - CHECK_MODE
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_three: '{{ tiny_prefix }} Three'
"Tag Two": 'two {{ tiny_prefix }}'
check_mode: true
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Update tags to verify idempotency
sns_topic:
name: '{{ sns_topic_topic_name }}'
tags:
tag_three: '{{ tiny_prefix }} Three'
"Tag Two": 'two {{ tiny_prefix }}'
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Update tags without purge - CHECK_MODE
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: no
tags:
tag_one: '{{ tiny_prefix }} One'
check_mode: true
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Update tags without purge
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: no
tags:
tag_one: '{{ tiny_prefix }} One'
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Remove all the tags - CHECK_MODE
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: yes
tags: {}
check_mode: true
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Remove all the tags
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: yes
tags: {}
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Update with CamelCase tags
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: no
tags:
"lowercase spaced": 'hello cruel world'
"Title Case": 'Hello Cruel World'
CamelCase: 'SimpleCamelCase'
snake_case: 'simple_snake_case'
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is changed

- name: Do not specify any tag to ensure previous tags are not removed
sns_topic:
name: '{{ sns_topic_topic_name }}'
purge_tags: no
register: sns_topic_tags

- assert:
that:
- sns_topic_tags is not changed

always:

- name: announce teardown start
Expand Down