From ce599bdf68bbd05b23ac4ed6cc46ae37208c698c Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Tue, 29 Mar 2022 15:10:42 +0200 Subject: [PATCH] rds_subnet_group: Add tags feature and enable check_mode (#562) rds_subnet_group: Add tags feature and enable check_mode SUMMARY rds_subnet_group: Add tags feature and enable check_mode Fixes: #552 Depends-On: ansible-collections/amazon.aws#553 ISSUE TYPE Feature Pull Request COMPONENT NAME rds_subnet_group Reviewed-by: Jill R Reviewed-by: Mark Chappell Reviewed-by: Alina Buzachis Reviewed-by: Mark Woolley Reviewed-by: Markus Bergholz --- ...-rds_subnet_group-tags-and-check_mode.yaml | 3 + plugins/modules/rds_subnet_group.py | 249 ++++++++-- .../targets/rds_subnet_group/tasks/main.yml | 2 +- .../targets/rds_subnet_group/tasks/tests.yml | 459 +++++++++++++++++- 4 files changed, 661 insertions(+), 52 deletions(-) create mode 100644 changelogs/fragments/562-rds_subnet_group-tags-and-check_mode.yaml diff --git a/changelogs/fragments/562-rds_subnet_group-tags-and-check_mode.yaml b/changelogs/fragments/562-rds_subnet_group-tags-and-check_mode.yaml new file mode 100644 index 00000000000..6fdaa2e6b87 --- /dev/null +++ b/changelogs/fragments/562-rds_subnet_group-tags-and-check_mode.yaml @@ -0,0 +1,3 @@ +minor_changes: +- rds_subnet_group - add ``tags`` feature (https://github.com/ansible-collections/community.aws/pull/562). +- rds_subnet_group - add ``check_mode`` (https://github.com/ansible-collections/community.aws/pull/562). diff --git a/plugins/modules/rds_subnet_group.py b/plugins/modules/rds_subnet_group.py index 7d789481c43..b0a9f8ae806 100644 --- a/plugins/modules/rds_subnet_group.py +++ b/plugins/modules/rds_subnet_group.py @@ -39,7 +39,21 @@ - Required when I(state=present). type: list elements: str -author: "Scott Anderson (@tastychutney)" + tags: + description: + - A hash/dictionary of tags to add to the new RDS subnet group or to add/remove from an existing one. + type: dict + version_added: 3.2.0 + purge_tags: + description: + - Whether or not to remove tags assigned to the RDS subnet group if not specified in the playbook. + - To remove all tags set I(tags) to an empty dictionary in conjunction with this. + default: True + type: bool + version_added: 3.2.0 +author: + - "Scott Anderson (@tastychutney)" + - "Alina Buzachis (@alinabuzachis)" extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 @@ -56,6 +70,18 @@ - subnet-aaaaaaaa - subnet-bbbbbbbb +- name: Add or change a subnet group and associate tags + community.aws.rds_subnet_group: + state: present + name: norwegian-blue + description: My Fancy Ex Parrot Subnet Group + subnets: + - subnet-aaaaaaaa + - subnet-bbbbbbbb + tags: + tag1: Tag1 + tag2: Tag2 + - name: Remove a subnet group community.aws.rds_subnet_group: state: absent @@ -63,6 +89,11 @@ ''' RETURN = r''' +changed: + description: True if listing the RDS subnet group succeeds. + type: bool + returned: always + sample: "false" subnet_group: description: Dictionary of DB subnet group values returned: I(state=present) @@ -72,46 +103,95 @@ description: The name of the DB subnet group (maintained for backward compatibility) returned: I(state=present) type: str + sample: "ansible-test-mbp-13950442" db_subnet_group_name: description: The name of the DB subnet group returned: I(state=present) type: str + sample: "ansible-test-mbp-13950442" description: description: The description of the DB subnet group (maintained for backward compatibility) returned: I(state=present) type: str + sample: "Simple description." db_subnet_group_description: description: The description of the DB subnet group returned: I(state=present) type: str + sample: "Simple description." vpc_id: description: The VpcId of the DB subnet group returned: I(state=present) type: str + sample: "vpc-0acb0ba033ff2119c" subnet_ids: description: Contains a list of Subnet IDs returned: I(state=present) type: list + sample: + "subnet-08c94870f4480797e" subnets: description: Contains a list of Subnet elements (@see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.describe_db_subnet_groups) # noqa returned: I(state=present) type: list + contains: + subnet_availability_zone: + description: Contains Availability Zone information. + returned: I(state=present) + type: dict + version_added: 3.2.0 + sample: + name: "eu-north-1b" + subnet_identifier: + description: The identifier of the subnet. + returned: I(state=present) + type: str + version_added: 3.2.0 + sample: "subnet-08c94870f4480797e" + subnet_outpost: + description: This value specifies the Outpost. + returned: I(state=present) + type: dict + version_added: 3.2.0 + sample: {} + subnet_status: + description: The status of the subnet. + returned: I(state=present) + type: str + version_added: 3.2.0 + sample: "Active" status: description: The status of the DB subnet group (maintained for backward compatibility) returned: I(state=present) type: str + sample: "Complete" subnet_group_status: description: The status of the DB subnet group returned: I(state=present) type: str + sample: "Complete" db_subnet_group_arn: description: The ARN of the DB subnet group returned: I(state=present) type: str + sample: "arn:aws:rds:eu-north-1:721066863947:subgrp:ansible-test-13950442" + tags: + description: The tags associated with the subnet group + returned: I(state=present) + type: dict + version_added: 3.2.0 + sample: + tag1: Tag1 + tag2: Tag2 ''' from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict -from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +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 AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.rds import get_tags +from ansible_collections.amazon.aws.plugins.module_utils.rds import ensure_tags try: @@ -125,7 +205,7 @@ def create_result(changed, subnet_group=None): return dict( changed=changed ) - result_subnet_group = dict(camel_dict_to_snake_dict(subnet_group)) + result_subnet_group = dict(subnet_group) result_subnet_group['name'] = result_subnet_group.get( 'db_subnet_group_name') result_subnet_group['description'] = result_subnet_group.get( @@ -133,15 +213,39 @@ def create_result(changed, subnet_group=None): result_subnet_group['status'] = result_subnet_group.get( 'subnet_group_status') result_subnet_group['subnet_ids'] = create_subnet_list( - subnet_group.get('Subnets')) + subnet_group.get('subnets')) return dict( changed=changed, subnet_group=result_subnet_group ) +@AWSRetry.jittered_backoff() +def _describe_db_subnet_groups_with_backoff(client, **kwargs): + paginator = client.get_paginator('describe_db_subnet_groups') + return paginator.paginate(**kwargs).build_full_result() + + +def get_subnet_group(client, module): + params = dict() + params['DBSubnetGroupName'] = module.params.get('name').lower() + + try: + _result = _describe_db_subnet_groups_with_backoff(client, **params) + except is_boto3_error_code('DBSubnetGroupNotFoundFault'): + return None + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, msg="Couldn't describe subnet groups.") + + if _result: + result = camel_dict_to_snake_dict(_result['DBSubnetGroups'][0]) + result['tags'] = get_tags(client, module, result['db_subnet_group_arn']) + + return result + + def create_subnet_list(subnets): - ''' + r''' Construct a list of subnet ids from a list of subnets dicts returned by boto3. Parameters: subnets (list): A list of subnets definitions. @@ -151,7 +255,7 @@ def create_subnet_list(subnets): ''' subnets_ids = [] for subnet in subnets: - subnets_ids.append(subnet.get('SubnetIdentifier')) + subnets_ids.append(subnet.get('subnet_identifier')) return subnets_ids @@ -161,64 +265,111 @@ def main(): name=dict(required=True), description=dict(required=False), subnets=dict(required=False, type='list', elements='str'), + tags=dict(required=False, type='dict'), + purge_tags=dict(type='bool', default=True), ) required_if = [('state', 'present', ['description', 'subnets'])] + module = AnsibleAWSModule( - argument_spec=argument_spec, required_if=required_if) + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True + ) + state = module.params.get('state') group_name = module.params.get('name').lower() group_description = module.params.get('description') group_subnets = module.params.get('subnets') or [] try: - conn = module.client('rds') + connection = module.client('rds', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: - module.fail_json_aws(e, 'Failed to instantiate AWS connection') + module.fail_json_aws(e, 'Failed to instantiate AWS connection.') + # Default. + changed = None result = create_result(False) + tags_update = False + subnet_update = False - try: - matching_groups = conn.describe_db_subnet_groups( - DBSubnetGroupName=group_name, MaxRecords=100).get('DBSubnetGroups') - except is_boto3_error_code('DBSubnetGroupNotFoundFault'): - # No existing subnet, create it if needed, else we can just exit. - if state == 'present': + if module.params.get("tags") is not None: + _tags = ansible_dict_to_boto3_tag_list(module.params.get("tags")) + else: + _tags = list() + + matching_groups = get_subnet_group(connection, module) + + if state == 'present': + if matching_groups: + # We have one or more subnets at this point. + + # Check if there is any tags update + tags_update = ensure_tags( + connection, + module, + matching_groups['db_subnet_group_arn'], + matching_groups['tags'], + module.params.get("tags"), + module.params['purge_tags'] + ) + + # Sort the subnet groups before we compare them + existing_subnets = create_subnet_list(matching_groups['subnets']) + existing_subnets.sort() + group_subnets.sort() + + # See if anything changed. + if ( + matching_groups['db_subnet_group_name'] != group_name or + matching_groups['db_subnet_group_description'] != group_description or + existing_subnets != group_subnets + ): + if not module.check_mode: + # Modify existing group. + try: + connection.modify_db_subnet_group( + aws_retry=True, + DBSubnetGroupName=group_name, + DBSubnetGroupDescription=group_description, + SubnetIds=group_subnets + ) + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: + module.fail_json_aws(e, 'Failed to update a subnet group.') + subnet_update = True + else: + if not module.check_mode: + try: + connection.create_db_subnet_group( + aws_retry=True, + DBSubnetGroupName=group_name, + DBSubnetGroupDescription=group_description, + SubnetIds=group_subnets, + Tags=_tags + ) + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: + module.fail_json_aws(e, 'Failed to create a new subnet group.') + subnet_update = True + elif state == 'absent': + if not module.check_mode: try: - new_group = conn.create_db_subnet_group( - DBSubnetGroupName=group_name, DBSubnetGroupDescription=group_description, SubnetIds=group_subnets) - result = create_result(True, new_group.get('DBSubnetGroup')) - except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: - module.fail_json_aws(e, 'Failed to create a new subnet group') - module.exit_json(**result) - except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except - module.fail_json_aws(e, 'Failed to get subnet groups description') - # We have one or more subnets at this point. - if state == 'absent': - try: - conn.delete_db_subnet_group(DBSubnetGroupName=group_name) - result = create_result(True) + connection.delete_db_subnet_group(aws_retry=True, DBSubnetGroupName=group_name) + except is_boto3_error_code('DBSubnetGroupNotFoundFault'): + module.exit_json(**result) + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, 'Failed to delete a subnet group.') + else: + subnet_group = get_subnet_group(connection, module) + if subnet_group: + subnet_update = True + result = create_result(subnet_update, subnet_group) module.exit_json(**result) - except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: - module.fail_json_aws(e, 'Failed to delete a subnet group') - - # Sort the subnet groups before we compare them - existing_subnets = create_subnet_list(matching_groups[0].get('Subnets')) - existing_subnets.sort() - group_subnets.sort() - # See if anything changed. - if (matching_groups[0].get('DBSubnetGroupName') == group_name and - matching_groups[0].get('DBSubnetGroupDescription') == group_description and - existing_subnets == group_subnets): - result = create_result(False, matching_groups[0]) - module.exit_json(**result) - # Modify existing group. - try: - changed_group = conn.modify_db_subnet_group( - DBSubnetGroupName=group_name, DBSubnetGroupDescription=group_description, SubnetIds=group_subnets) - result = create_result(True, changed_group.get('DBSubnetGroup')) - module.exit_json(**result) - except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: - module.fail_json_aws(e, 'Failed to update a subnet group') + + subnet_update = True + + subnet_group = get_subnet_group(connection, module) + changed = tags_update or subnet_update + result = create_result(changed, subnet_group) + module.exit_json(**result) if __name__ == '__main__': diff --git a/tests/integration/targets/rds_subnet_group/tasks/main.yml b/tests/integration/targets/rds_subnet_group/tasks/main.yml index 664d78edeee..ff31d014673 100644 --- a/tests/integration/targets/rds_subnet_group/tasks/main.yml +++ b/tests/integration/targets/rds_subnet_group/tasks/main.yml @@ -64,7 +64,7 @@ register: subnets - set_fact: - subnet_ids: '{{ subnets | community.general.json_query("results[].subnet.id") | list }}' + subnet_ids: '{{ subnets.results | map(attribute="subnet.id") | list }}' # ============================================================ diff --git a/tests/integration/targets/rds_subnet_group/tasks/tests.yml b/tests/integration/targets/rds_subnet_group/tasks/tests.yml index 0b4e3d1b52a..7018448c415 100644 --- a/tests/integration/targets/rds_subnet_group/tasks/tests.yml +++ b/tests/integration/targets/rds_subnet_group/tasks/tests.yml @@ -1,8 +1,21 @@ --- -# XXX rds_subnet_group doesn't support check_mode yet - # ============================================================ # Basic creation +- name: 'Create a subnet group - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + check_mode: true + register: result + +- assert: + that: + - result is changed + - name: 'Create a subnet group' rds_subnet_group: state: present @@ -23,6 +36,21 @@ - subnet_ids[0] in result.subnet_group.subnet_ids - subnet_ids[1] in result.subnet_group.subnet_ids +- name: 'Create a subnet group (idempotency) - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed + - name: 'Create a subnet group (idempotency)' rds_subnet_group: state: present @@ -45,6 +73,20 @@ # ============================================================ # Update description +- name: 'Update subnet group description - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + check_mode: true + register: result + +- assert: + that: + - result is changed - name: 'Update subnet group description' rds_subnet_group: @@ -65,6 +107,21 @@ - result.subnet_group.subnet_ids | length == 2 - subnet_ids[0] in result.subnet_group.subnet_ids - subnet_ids[1] in result.subnet_group.subnet_ids + +- name: 'Update subnet group description (idempotency) - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed - name: 'Update subnet group description (idempotency)' rds_subnet_group: @@ -85,6 +142,21 @@ - result.subnet_group.subnet_ids | length == 2 - subnet_ids[0] in result.subnet_group.subnet_ids - subnet_ids[1] in result.subnet_group.subnet_ids + +- name: 'Restore subnet group description - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + check_mode: true + register: result + +- assert: + that: + - result is changed - name: 'Restore subnet group description' rds_subnet_group: @@ -108,6 +180,20 @@ # ============================================================ # Update subnets +- name: 'Update subnet group list - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + check_mode: true + register: result + +- assert: + that: + - result is changed - name: 'Update subnet group list' rds_subnet_group: @@ -129,6 +215,21 @@ - subnet_ids[2] in result.subnet_group.subnet_ids - subnet_ids[3] in result.subnet_group.subnet_ids +- name: 'Update subnet group list (idempotency) - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed + - name: 'Update subnet group list (idempotency)' rds_subnet_group: state: present @@ -149,6 +250,23 @@ - subnet_ids[2] in result.subnet_group.subnet_ids - subnet_ids[3] in result.subnet_group.subnet_ids +- name: 'Add more subnets subnet group list - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + check_mode: true + register: result + +- assert: + that: + - result is changed + - name: 'Add more subnets subnet group list' rds_subnet_group: state: present @@ -173,6 +291,23 @@ - subnet_ids[2] in result.subnet_group.subnet_ids - subnet_ids[3] in result.subnet_group.subnet_ids +- name: 'Add more members to subnet group list (idempotency) - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed + - name: 'Add more members to subnet group list (idempotency)' rds_subnet_group: state: present @@ -197,8 +332,317 @@ - subnet_ids[2] in result.subnet_group.subnet_ids - subnet_ids[3] in result.subnet_group.subnet_ids +# ============================================================ +# Add tags to subnets +- name: 'Update subnet with tags - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + check_mode: true + register: result + +- assert: + that: + - result is changed + +- name: 'Update subnet with tags' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 2 + - result.subnet_group.tags["tag_one"] == '{{ resource_prefix }} One' + - result.subnet_group.tags["Tag Two"] == 'two {{ resource_prefix }}' + +- name: 'Update subnet with tags (idempotency) - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed + +- name: 'Update subnet with tags (idempotency)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 2 + - result.subnet_group.tags["tag_one"] == '{{ resource_prefix }} One' + - result.subnet_group.tags["Tag Two"] == 'two {{ resource_prefix }}' + +- name: 'Update (add/remove) tags - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_three: '{{ resource_prefix }} Three' + "Tag Two": 'two {{ resource_prefix }}' + check_mode: true + register: result + +- assert: + that: + - result is changed + +- name: 'Update (add/remove) tags' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + tag_three: '{{ resource_prefix }} Three' + "Tag Two": 'two {{ resource_prefix }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 2 + - result.subnet_group.tags["tag_three"] == '{{ resource_prefix }} Three' + - result.subnet_group.tags["Tag Two"] == 'two {{ resource_prefix }}' + +- name: 'Update tags without purge - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + purge_tags: no + tags: + tag_one: '{{ resource_prefix }} One' + check_mode: true + register: result + +- assert: + that: + - result is changed + +- name: 'Update tags without purge' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + purge_tags: no + tags: + tag_one: '{{ resource_prefix }} One' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 3 + - result.subnet_group.tags["tag_three"] == '{{ resource_prefix }} Three' + - result.subnet_group.tags["Tag Two"] == 'two {{ resource_prefix }}' + - result.subnet_group.tags["tag_one"] == '{{ resource_prefix }} One' + +- name: 'Remove all the tags - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: {} + check_mode: true + register: result + +- assert: + that: + - result is changed + +- name: 'Remove all the tags' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: {} + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + +- name: 'Update with CamelCase tags - CHECK_MODE' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + "lowercase spaced": 'hello cruel world' + "Title Case": 'Hello Cruel World' + CamelCase: 'SimpleCamelCase' + snake_case: 'simple_snake_case' + check_mode: true + register: result + +- assert: + that: + - result is changed + +- name: 'Update with CamelCase tags' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + tags: + "lowercase spaced": 'hello cruel world' + "Title Case": 'Hello Cruel World' + CamelCase: 'SimpleCamelCase' + snake_case: 'simple_snake_case' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 4 + - result.subnet_group.tags["lowercase spaced"] == 'hello cruel world' + - result.subnet_group.tags["Title Case"] == 'Hello Cruel World' + - result.subnet_group.tags["CamelCase"] == 'SimpleCamelCase' + - result.subnet_group.tags["snake_case"] == 'simple_snake_case' + +- name: 'Do not specify any tag to ensure previous tags are not removed' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - '"tags" in result.subnet_group' + - result.subnet_group.tags | length == 4 + - result.subnet_group.tags["lowercase spaced"] == 'hello cruel world' + - result.subnet_group.tags["Title Case"] == 'Hello Cruel World' + - result.subnet_group.tags["CamelCase"] == 'SimpleCamelCase' + - result.subnet_group.tags["snake_case"] == 'simple_snake_case' + + # ============================================================ # Deletion +- name: 'Delete a subnet group - CHECK_MODE' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + check_mode: true + register: result + +- assert: + that: + - result is changed - name: 'Delete a subnet group' rds_subnet_group: @@ -210,6 +654,17 @@ that: - result is changed +- name: 'Delete a subnet group - CHECK_MODE (idempotency)' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + check_mode: true + register: result + +- assert: + that: + - result is not changed + - name: 'Delete a subnet group (idempotency)' rds_subnet_group: state: absent