Skip to content

Commit

Permalink
wafv2_ip_set - add support for updating tags (#1205)
Browse files Browse the repository at this point in the history
wafv2_ip_set - add support for updating tags

SUMMARY

Added support for purge_tags
Added tags to return values
Added support for updating tags
Moved to common docs_fragment for tagging

ISSUE TYPE

Feature Pull Request

COMPONENT NAME
plugins/module_utils/wafv2.py
plugins/modules/wafv2_ip_set.py
plugins/modules/wafv2_ip_set_info.py
ADDITIONAL INFORMATION
Depends on : mattclay/aws-terminator#213

Reviewed-by: Alina Buzachis <None>
Reviewed-by: Markus Bergholz <git@osuv.de>
  • Loading branch information
tremble committed Jun 3, 2022
1 parent 11fcdea commit 36d8398
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 25 deletions.
5 changes: 5 additions & 0 deletions changelogs/fragments/1205-tagging-wafv2_ip_set.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
minor_changes:
- wafv2_ip_set - Added support for ``purge_tags`` parameter (https://github.com/ansible-collections/community.aws/pull/1205).
- wafv2_ip_set - Added support for updating tags (https://github.com/ansible-collections/community.aws/pull/1205).
- wafv2_ip_set - Added support for returning tags (https://github.com/ansible-collections/community.aws/pull/1205).
- wafv2_ip_set_info - Added support for returning tags (https://github.com/ansible-collections/community.aws/pull/1205).
61 changes: 59 additions & 2 deletions plugins/module_utils/wafv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,63 @@
except ImportError:
pass # caught by AnsibleAWSModule

from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags


@AWSRetry.jittered_backoff()
def _list_tags(wafv2, arn, fail_json_aws, next_marker=None):
params = dict(ResourceARN=arn)
if next_marker:
params['NextMarker'] = next_marker
try:
return wafv2.list_tags_for_resource(**params)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 tags")


def describe_wafv2_tags(wafv2, arn, fail_json_aws):
next_marker = None
tag_list = []
# there is currently no paginator for wafv2
while True:
responce = _list_tags(wafv2, arn, fail_json_aws)
next_marker = responce.get('NextMarker', None)
tag_info = responce.get('TagInfoForResource', {})
tag_list.extend(tag_info.get('TagList', []))
if not next_marker:
break
return boto3_tag_list_to_ansible_dict(tag_list)


def ensure_wafv2_tags(wafv2, arn, tags, purge_tags, fail_json_aws, check_mode):
if tags is None:
return False

current_tags = describe_wafv2_tags(wafv2, arn, fail_json_aws)
tags_to_add, tags_to_remove = compare_aws_tags(current_tags, tags, purge_tags)
if not tags_to_add and not tags_to_remove:
return False

if check_mode:
return True

if tags_to_add:
try:
boto3_tags = ansible_dict_to_boto3_tag_list(tags_to_add)
wafv2.tag_resource(ResourceARN=arn, Tags=boto3_tags)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to add wafv2 tags")
if tags_to_remove:
try:
wafv2.untag_resource(ResourceARN=arn, TagKeys=tags_to_remove)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to remove wafv2 tags")

return True


def wafv2_list_web_acls(wafv2, scope, fail_json_aws, nextmarker=None):
# there is currently no paginator for wafv2
Expand All @@ -19,7 +76,7 @@ def wafv2_list_web_acls(wafv2, scope, fail_json_aws, nextmarker=None):
try:
response = wafv2.list_web_acls(**req_obj)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 web acl.")
fail_json_aws(e, msg="Failed to list wafv2 web acl")

if response.get('NextMarker'):
response['WebACLs'] += wafv2_list_web_acls(wafv2, scope, fail_json_aws, nextmarker=response.get('NextMarker')).get('WebACLs')
Expand All @@ -38,7 +95,7 @@ def wafv2_list_rule_groups(wafv2, scope, fail_json_aws, nextmarker=None):
try:
response = wafv2.list_rule_groups(**req_obj)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 rule group.")
fail_json_aws(e, msg="Failed to list wafv2 rule group")

if response.get('NextMarker'):
response['RuleGroups'] += wafv2_list_rule_groups(wafv2, scope, fail_json_aws, nextmarker=response.get('NextMarker')).get('RuleGroups')
Expand Down
49 changes: 30 additions & 19 deletions plugins/modules/wafv2_ip_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,19 @@
from the IP set. The entire IP set itself will stay present.
type: list
elements: str
tags:
description:
- Key value pairs to associate with the resource.
- Currently tags are not visible. Nor in the web ui, nor via cli and nor in boto3.
required: false
type: dict
purge_addresses:
description:
- When set to C(no), keep the existing addresses in place. Will modify and add, but will not delete.
default: yes
type: bool
notes:
- Support for I(purge_tags) was added in release 4.0.0.
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
- amazon.aws.aws
- amazon.aws.ec2
- amazon.aws.tags
'''

Expand Down Expand Up @@ -125,6 +123,8 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
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 camel_dict_to_snake_dict
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
from ansible_collections.community.aws.plugins.module_utils.wafv2 import ensure_wafv2_tags


class IpSet:
Expand All @@ -133,15 +133,18 @@ def __init__(self, wafv2, name, scope, fail_json_aws):
self.name = name
self.scope = scope
self.fail_json_aws = fail_json_aws
self.existing_set, self.id, self.locktoken = self.get_set()
self.existing_set, self.id, self.locktoken, self.arn = self.get_set()

def description(self):
return self.existing_set.get('Description')

def _format_set(self, ip_set):
if ip_set is None:
return None
return camel_dict_to_snake_dict(self.existing_set, ignore_list=['tags'])

def get(self):
if self.existing_set:
return camel_dict_to_snake_dict(self.existing_set)
return None
return self._format_set(self.existing_set)

def remove(self):
try:
Expand Down Expand Up @@ -174,8 +177,8 @@ def create(self, description, ip_address_version, addresses, tags):
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to create wafv2 ip set.")

self.existing_set, self.id, self.locktoken = self.get_set()
return camel_dict_to_snake_dict(self.existing_set)
self.existing_set, self.id, self.locktoken, self.arn = self.get_set()
return self._format_set(self.existing_set)

def update(self, description, addresses):
req_obj = {
Expand All @@ -194,13 +197,14 @@ def update(self, description, addresses):
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to update wafv2 ip set.")

self.existing_set, self.id, self.locktoken = self.get_set()
return camel_dict_to_snake_dict(self.existing_set)
self.existing_set, self.id, self.locktoken, self.arn = self.get_set()
return self._format_set(self.existing_set)

def get_set(self):
response = self.list()
existing_set = None
id = None
arn = None
locktoken = None
for item in response.get('IPSets'):
if item.get('Name') == self.name:
Expand All @@ -216,8 +220,10 @@ def get_set(self):
).get('IPSet')
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to get wafv2 ip set.")
tags = describe_wafv2_tags(self.wafv2, arn, self.fail_json_aws)
existing_set['tags'] = tags

return existing_set, id, locktoken
return existing_set, id, locktoken, arn

def list(self, Nextmarker=None):
# there is currently no paginator for wafv2
Expand Down Expand Up @@ -275,8 +281,9 @@ def main():
description=dict(type='str'),
ip_address_version=dict(type='str', choices=['IPV4', 'IPV6']),
addresses=dict(type='list', elements='str'),
tags=dict(type='dict'),
purge_addresses=dict(type='bool', default=True)
tags=dict(type='dict', aliases=['resource_tags']),
purge_tags=dict(type='bool', default=True),
purge_addresses=dict(type='bool', default=True),
)

module = AnsibleAWSModule(
Expand All @@ -292,6 +299,7 @@ def main():
ip_address_version = module.params.get("ip_address_version")
addresses = module.params.get("addresses")
tags = module.params.get("tags")
purge_tags = module.params.get("purge_tags")
purge_addresses = module.params.get("purge_addresses")
check_mode = module.check_mode

Expand All @@ -303,7 +311,9 @@ def main():
ip_set = IpSet(wafv2, name, scope, module.fail_json_aws)

if state == 'present':

if ip_set.get():
tags_updated = ensure_wafv2_tags(wafv2, ip_set.arn, tags, purge_tags, module.fail_json_aws, module.check_mode)
change, addresses = compare(ip_set.get(), addresses, purge_addresses, state)
if (change or ip_set.description() != description) and not check_mode:
retval = ip_set.update(
Expand All @@ -312,6 +322,7 @@ def main():
)
else:
retval = ip_set.get()
change |= tags_updated
else:
if not check_mode:
retval = ip_set.create(
Expand Down
8 changes: 5 additions & 3 deletions plugins/modules/wafv2_ip_set_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags


def list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=None):
Expand All @@ -93,7 +94,7 @@ def list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=None):
if response.get('NextMarker'):
response['IPSets'] += list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=response.get('NextMarker')).get('IPSets')
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 ip set.")
fail_json_aws(e, msg="Failed to list wafv2 ip set")
return response


Expand All @@ -105,7 +106,7 @@ def get_ip_set(wafv2, name, scope, id, fail_json_aws):
Id=id
)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 ip set.")
fail_json_aws(e, msg="Failed to get wafv2 ip set")
return response


Expand Down Expand Up @@ -134,13 +135,14 @@ def main():
for item in response.get('IPSets'):
if item.get('Name') == name:
id = item.get('Id')
arn = item.get('ARN')

retval = {}
existing_set = None
if id:
existing_set = get_ip_set(wafv2, name, scope, id, module.fail_json_aws)
retval = camel_dict_to_snake_dict(existing_set.get('IPSet'))

retval['tags'] = describe_wafv2_tags(wafv2, arn, module.fail_json_aws) or {}
module.exit_json(**retval)


Expand Down
3 changes: 2 additions & 1 deletion tests/integration/targets/wafv2_ip_set/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"

block:
- name: check_mode create ip set
wafv2_ip_set:
Expand Down Expand Up @@ -177,6 +176,8 @@
that:
- out.addresses | count == 1

- include_tasks: 'tagging.yml'

- name: delete ip set
wafv2_ip_set:
name: "{{ ip_set_name }}"
Expand Down
Loading

0 comments on commit 36d8398

Please sign in to comment.