From 0fec3b1ac0868bf64f09ec4c50bf7a1b080137f6 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Mon, 18 Jan 2021 11:56:57 +0000 Subject: [PATCH] Tags feature: support tags specification for NAT gateway (#345) * implement tags feature for NAT gateway * add integration test tasks for tags feature * refactor integration tests (overall) removing hard-coded parameters * add missing integration test tasks without CHECK_MODE * include until loop for some tasks as they failed during the integration * added code to support tags in ec2_vap_nat_gateway - return error 'NoneType' object has no attribute 'get' because of curr_tags seems to remain None * removed tests in check_mode because not working due to DRY_RUN_GATEWAY * Addressed reviewers comments Signed-off-by: Alina Buzachis --- plugins/modules/ec2_vpc_nat_gateway.py | 151 ++++- .../ec2_vpc_nat_gateway/defaults/main.yml | 5 + .../ec2_vpc_nat_gateway/tasks/main.yml | 620 +++++++++++++++--- 3 files changed, 679 insertions(+), 97 deletions(-) create mode 100644 tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 9072a8e32b6..c4e3cbfd797 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -48,6 +48,19 @@ required: false default: false type: bool + tags: + description: + - A dict of tags to apply to the internet gateway. + - To remove all tags set I(tags={}) and I(purge_tags=true). + aliases: [ 'resource_tags' ] + type: dict + version_added: 1.4.0 + purge_tags: + description: + - Remove tags not listed in I(tags). + type: bool + default: true + version_added: 1.4.0 release_eip: description: - Deallocate the EIP from the VPC. @@ -153,6 +166,17 @@ wait: yes wait_timeout: 300 region: ap-southeast-2 + +- name: Create new nat gateway using an allocation-id and tags. + community.aws.ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + allocation_id: eipalloc-12345678 + region: ap-southeast-2 + tags: + Tag1: tag1 + Tag2: tag2 + register: new_nat_gateway ''' RETURN = ''' @@ -176,6 +200,13 @@ returned: In all cases. type: str sample: "available" +tags: + description: The tags associated the VPC NAT Gateway. + type: dict + returned: When tags are present. + sample: + tags: + "Ansible": "Test" vpc_id: description: id of the VPC. returned: In all cases. @@ -204,11 +235,17 @@ except ImportError: pass # Handled by AnsibleAWSModule -from ansible.module_utils._text import to_native + +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry 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 camel_dict_to_snake_dict - +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list +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_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags +from ansible.module_utils.six import string_types +from ansible.module_utils._text import to_native DRY_RUN_GATEWAYS = [ { @@ -451,6 +488,7 @@ def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, allocation_id_exists = False gateways = [] states = ['available', 'pending'] + gws_retrieved, err_msg, gws = ( get_nat_gateways( client, subnet_id, states=states, check_mode=check_mode @@ -609,7 +647,7 @@ def release_address(client, allocation_id, check_mode=False): return ip_released, err_msg -def create(client, subnet_id, allocation_id, client_token=None, +def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_token=None, wait=False, wait_timeout=0, if_exist_do_not_create=False, check_mode=False): """Create an Amazon NAT Gateway. @@ -680,7 +718,6 @@ def create(client, subnet_id, allocation_id, client_token=None, result['create_time'] = datetime.datetime.utcnow() result['nat_gateway_addresses'][0]['allocation_id'] = allocation_id result['subnet_id'] = subnet_id - success = True changed = True create_time = result['create_time'].replace(tzinfo=None) @@ -689,15 +726,18 @@ def create(client, subnet_id, allocation_id, client_token=None, elif wait: success, err_msg, result = ( wait_for_status( - client, wait_timeout, result['nat_gateway_id'], 'available', - check_mode=check_mode + client, wait_timeout, result['nat_gateway_id'], + 'available', check_mode=check_mode ) ) if success: err_msg = ( 'NAT gateway {0} created'.format(result['nat_gateway_id']) ) - + result['tags'], tags_update_exists = ensure_tags( + client, module, nat_gw_id=result['nat_gateway_id'], tags=tags, + purge_tags=purge_tags, check_mode=check_mode + ) except is_boto3_error_code('IdempotentParameterMismatch'): err_msg = ( 'NAT Gateway does not support update and token has already been provided: ' + err_msg @@ -714,7 +754,7 @@ def create(client, subnet_id, allocation_id, client_token=None, return success, changed, err_msg, result -def pre_create(client, subnet_id, allocation_id=None, eip_address=None, +def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, eip_address=None, if_exist_do_not_create=False, wait=False, wait_timeout=0, client_token=None, check_mode=False): """Create an Amazon NAT Gateway. @@ -772,14 +812,18 @@ def pre_create(client, subnet_id, allocation_id=None, eip_address=None, results = list() if not allocation_id and not eip_address: - existing_gateways, allocation_id_exists = ( - gateway_in_subnet_exists(client, subnet_id, check_mode=check_mode) - ) - + existing_gateways, allocation_id_exists = (gateway_in_subnet_exists(client, subnet_id, check_mode=check_mode)) if len(existing_gateways) > 0 and if_exist_do_not_create: + results = existing_gateways[0] + results['tags'], tags_update_exists = ensure_tags(client, module, results['nat_gateway_id'], tags, purge_tags, check_mode) + + if tags_update_exists: + success = True + changed = True + return success, changed, err_msg, results + success = True changed = False - results = existing_gateways[0] err_msg = ( 'NAT Gateway {0} already exists in subnet_id {1}' .format( @@ -805,16 +849,22 @@ def pre_create(client, subnet_id, allocation_id=None, eip_address=None, success = False changed = False return success, changed, err_msg, dict() - existing_gateways, allocation_id_exists = ( gateway_in_subnet_exists( client, subnet_id, allocation_id, check_mode=check_mode ) ) + if len(existing_gateways) > 0 and (allocation_id_exists or if_exist_do_not_create): + results = existing_gateways[0] + results['tags'], tags_update_exists = ensure_tags(client, module, results['nat_gateway_id'], tags, purge_tags, check_mode) + if tags_update_exists: + success = True + changed = True + return success, changed, err_msg, results + success = True changed = False - results = existing_gateways[0] err_msg = ( 'NAT Gateway {0} already exists in subnet_id {1}' .format( @@ -824,7 +874,7 @@ def pre_create(client, subnet_id, allocation_id=None, eip_address=None, return success, changed, err_msg, results success, changed, err_msg, results = create( - client, subnet_id, allocation_id, client_token, + client, module, subnet_id, allocation_id, tags, purge_tags, client_token, wait, wait_timeout, if_exist_do_not_create, check_mode=check_mode ) @@ -919,8 +969,7 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, if release_eip: eip_released, eip_err = ( - release_address(client, allocation_id, check_mode) - ) + release_address(client, allocation_id, check_mode)) if not eip_released: err_msg = ( "{0}: Failed to release EIP {1}: {2}" @@ -931,6 +980,64 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, return success, changed, err_msg, results +def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): + final_tags = [] + changed = False + + filters = ansible_dict_to_boto3_filter_list({'resource-id': nat_gw_id, 'resource-type': 'natgateway'}) + cur_tags = None + try: + cur_tags = client.describe_tags(aws_retry=True, Filters=filters) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, 'Couldnt describe tags') + if tags is None: + return boto3_tag_list_to_ansible_dict(cur_tags['Tags']), changed + + to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags) + final_tags = boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')) + + if to_update: + try: + if check_mode: + # update tags + final_tags.update(to_update) + else: + client.create_tags( + aws_retry=True, + Resources=[nat_gw_id], + Tags=ansible_dict_to_boto3_tag_list(to_update) + ) + + changed = True + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Couldn't create tags") + + if to_delete: + try: + if check_mode: + # update tags + for key in to_delete: + del final_tags[key] + else: + tags_list = [] + for key in to_delete: + tags_list.append({'Key': key}) + + client.delete_tags(aws_retry=True, Resources=[nat_gw_id], Tags=tags_list) + + changed = True + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Couldn't delete tags") + + if not check_mode and (to_update or to_delete): + try: + response = client.describe_tags(aws_retry=True, Filters=filters) + final_tags = boto3_tag_list_to_ansible_dict(response.get('Tags')) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Couldn't describe tags") + return final_tags, changed + + def main(): argument_spec = dict( subnet_id=dict(type='str'), @@ -943,6 +1050,8 @@ def main(): release_eip=dict(type='bool', default=False), nat_gateway_id=dict(type='str'), client_token=dict(type='str'), + tags=dict(required=False, type='dict', aliases=['resource_tags']), + purge_tags=dict(default=True, type='bool'), ) module = AnsibleAWSModule( argument_spec=argument_spec, @@ -965,9 +1074,11 @@ def main(): release_eip = module.params.get('release_eip') client_token = module.params.get('client_token') if_exist_do_not_create = module.params.get('if_exist_do_not_create') + tags = module.params.get('tags') + purge_tags = module.params.get('purge_tags') try: - client = module.client('ec2') + client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Failed to connect to AWS') @@ -977,7 +1088,7 @@ def main(): if state == 'present': success, changed, err_msg, results = ( pre_create( - client, subnet_id, allocation_id, eip_address, + client, module, subnet_id, tags, purge_tags, allocation_id, eip_address, if_exist_do_not_create, wait, wait_timeout, client_token, check_mode=check_mode ) diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml new file mode 100644 index 00000000000..6ea912c898e --- /dev/null +++ b/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml @@ -0,0 +1,5 @@ +--- +vpc_name: "{{ resource_prefix }}-vpc" +vpc_seed: "{{ resource_prefix }}" +vpc_cidr: "10.0.0.0/16" +subnet_cidr: "10.0.{{ 256 | random(seed=vpc_seed) }}.0/24" diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml index 7cb7e986e0a..2b411340149 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -3,80 +3,546 @@ # They take advantage of hard-coded results within the module to trigger both changed and unchanged responses. # They were migrated to maintain test coverage while removing unit tests that depended on use of TaskQueueManager. -- name: Create new nat gateway with eip allocation-id - ec2_vpc_nat_gateway: - subnet_id: subnet-12345678 - allocation_id: eipalloc-12345678 - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - nat_gateway.changed - -- name: Create new nat gateway with eip allocation-id - ec2_vpc_nat_gateway: - subnet_id: subnet-123456789 - allocation_id: eipalloc-1234567 - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - not nat_gateway.changed - -- name: Create new nat gateway with eip address - ec2_vpc_nat_gateway: - subnet_id: subnet-12345678 - eip_address: 55.55.55.55 - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - nat_gateway.changed - -- name: Create new nat gateway with eip address - ec2_vpc_nat_gateway: - subnet_id: subnet-123456789 - eip_address: 55.55.55.55 - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - not nat_gateway.changed - -- name: Create new nat gateway only if one does not exist already - ec2_vpc_nat_gateway: - if_exist_do_not_create: yes - subnet_id: subnet-123456789 - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - not nat_gateway.changed - -- name: Delete Nat Gateway - ec2_vpc_nat_gateway: - nat_gateway_id: nat-123456789 - state: absent - wait: yes - region: us-west-2 - register: nat_gateway - check_mode: yes - -- assert: - that: - - nat_gateway.changed +--- +# ============================================================ +# Known issues: +# +# `check_mode` is not working correctly due to the hard-coded DRY_RUN_GATEWAY (module code). The values passed here, +# when CHECK_MODE is used, don't correspond to those used for the DRY_RUN_GATEWAY and all test +# (except when the NAT gateway is created for the first time) fail. +# +# `Create new NAT gateway with eip address` - when the task is run for the first time, do we expect changed=true? +# As we use the same EIP, I think changed should be false (if this is correct, lines 194-218 are redundant and +# lines 177 and 190 should report `not create_ngw.changed`). +# ============================================================ + +- name: ec2_vpc_nat_gateway tests + module_defaults: + group/aws: + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token | default(omit) }}" + region: "{{ aws_region }}" + collections: + - amazon.aws + + block: + + # ============================================================ + - name: Create a VPC + ec2_vpc_net: + name: "{{ vpc_name }}" + state: present + cidr_block: "{{ vpc_cidr }}" + register: vpc_result + + - name: Assert success + assert: + that: + - vpc_result is successful + + - name: "set fact: VPC ID" + set_fact: + vpc_id: "{{ vpc_result.vpc.id }}" + + # ============================================================ + - name: Allocate a new EIP + ec2_eip: + in_vpc: true + reuse_existing_ip_allowed: true + tag_name: FREE + register: eip_result + + - name: Assert success + assert: + that: + - eip_result is successful + + - name: "set fact: EIP allocation ID and EIP public IP" + set_fact: + eip_address: "{{ eip_result.public_ip }}" + allocation_id: "{{ eip_result.allocation_id }}" + + + # ============================================================ + - name: Create subnet and associate to the VPC + ec2_vpc_subnet: + state: present + vpc_id: "{{ vpc_id }}" + cidr: "{{ subnet_cidr }}" + register: subnet_result + + - name: Assert success + assert: + that: + - subnet_result is successful + + - name: "set fact: VPC subnet ID" + set_fact: + subnet_id: "{{ subnet_result.subnet.id }}" + + + # ============================================================ + - name: Search for NAT gateways by subnet - no matches + ec2_vpc_nat_gateway_info: + filters: + subnet-id: "{{ subnet_id }}" + state: ['available'] + register: existing_ngws + retries: 10 + until: existing_ngws is not failed + + - name: Assert no NAT gateway found + assert: + that: + - existing_ngws is successful + - (existing_ngws.result|length) == 0 + + + + # ============================================================ + - name: Create IGW + ec2_vpc_igw: + vpc_id: "{{ vpc_id }}" + register: create_igw + + - name: Assert success + assert: + that: + - create_igw is successful + + + # ============================================================ + - name: Create new NAT gateway with eip allocation-id + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + wait: yes + register: create_ngw + retries: 10 + until: create_ngw is not failed + + - name: Assert creation happened (expected changed=true) + assert: + that: + - create_ngw.changed + + - name: "set facts: NAT gateway ID" + set_fact: + nat_gateway_id: "{{ create_ngw.nat_gateway_id }}" + network_interface_id: "{{ create_ngw.nat_gateway_addresses[0].network_interface_id }}" + + # - name: Create new NAT gateway with eip allocation-id - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # wait: yes + # register: create_ngw + # check_mode: yes + # + # - name: Assert creation happened (expected changed=true) - CHECK_MODE + # assert: + # that: + # - create_ngw.changed + + # ============================================================ + - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + wait: yes + register: create_ngw + retries: 10 + until: create_ngw is not failed + + - name: Assert recreation would do nothing (expected changed=false) + assert: + that: + - not create_ngw.changed + + # - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # wait: yes + # register: create_ngw + # check_mode: yes + + # - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE + # assert: + # that: + # - not create_ngw.changed + + + # ============================================================ + #- name: Create new NAT gateway with eip address + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # eip_address: "{{ eip_address }}" + # wait: yes + # register: create_ngw + # + #- name: Assert creation happened (expected changed=true) + # assert: + # that: + # - create_ngw.changed + + # - name: Create new nat gateway with eip address - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # eip_address: "{{ eip_address }}" + # wait: yes + # register: create_ngw + # check_mode: yes + + # - name: Assert creation happened (expected changed=true) - CHECK_MODE + # assert: + # that: + # - create_ngw.changed + + + # ============================================================ + # - name: Trying this again for idempotency - create new nat gateway with eip address + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # eip_address: "{{ eip_address }}" + # wait: yes + # register: create_ngw + + # - name: Assert recreation would do nothing (expected changed=false) + # assert: + # that: + # - not create_ngw.changed + + # - name: Trying this again for idempotency - create new nat gateway with eip address - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # eip_address: "{{ eip_address }}" + # wait: yes + # register: create_ngw + # check_mode: yes + + # - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE + # assert: + # that: + # - not create_ngw.changed + + + # ============================================================ + - name: Create new NAT gateway only if one does not exist already + ec2_vpc_nat_gateway: + if_exist_do_not_create: yes + subnet_id: "{{ subnet_id }}" + wait: yes + register: create_ngw + retries: 10 + until: create_ngw is not failed + + - name: Assert recreation would do nothing (expected changed=false) + assert: + that: + - not create_ngw.changed + + # - name: Create new nat gateway only if one does not exist already - CHECK_MODE + # ec2_vpc_nat_gateway: + # if_exist_do_not_create: yes + # subnet_id: "{{ subnet_id }}" + # wait: yes + # register: create_ngw + # check_mode: yes + + # - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE + # assert: + # that: + # - not create_ngw.changed + + + # ============================================================ + - name: Delete NAT gateway + ec2_vpc_nat_gateway: + nat_gateway_id: "{{ nat_gateway_id }}" + state: absent + wait: yes + register: delete_nat_gateway + retries: 10 + until: delete_nat_gateway is not failed + + - name: Assert state=absent (expected changed=true) + assert: + that: + - delete_nat_gateway.changed + + # - name: Delete NAT gateway - CHECK_MODE + # ec2_vpc_nat_gateway: + # nat_gateway_id: "{{ nat_gateway_id }}" + # state: absent + # wait: yes + # register: delete_nat_gateway + # check_mode: yes + + # - name: Assert state=absent (expected changed=true) - CHECK_MODE + # assert: + # that: + # - delete_nat_gateway.changed + + # ============================================================ + - name: Create new NAT gateway with eip allocation-id and tags + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + wait: yes + register: create_ngw + + - name: Assert creation happened (expected changed=true) + assert: + that: + - create_ngw.changed + + # - name: Create new NAT gateway with eip allocation-id and tags - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # tags: + # tag_one: '{{ resource_prefix }} One' + # "Tag Two": 'two {{ resource_prefix }}' + # wait: yes + # register: create_ngw + # check_mode: yes + + # - name: Assert creation happened (expected changed=true) - CHECK_MODE + # assert: + # that: + # - create_ngw.changed + + + # ============================================================ + - name: Update the tags (no change) + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + tags: + tag_one: '{{ resource_prefix }} One' + "Tag Two": 'two {{ resource_prefix }}' + wait: yes + register: update_tags_ngw + + - name: assert tag update would do nothing (expected changed=false) + assert: + that: + - not update_tags_ngw.changed + + # - name: Update the tags (no change) - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # tags: + # tag_one: '{{ resource_prefix }} One' + # "Tag Two": 'two {{ resource_prefix }}' + # wait: yes + # register: update_tags_ngw + # check_mode: yes + + # - name: assert tag update would do nothing (expected changed=false) - CHECK_MODE + # assert: + # that: + # - not update_tags_ngw.changed + + + # ============================================================ + - name: Update the tags - remove and add + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + tags: + tag_three: '{{ resource_prefix }} Three' + "Tag Two": 'two {{ resource_prefix }}' + wait: yes + register: update_tags_ngw + + - name: Assert tag update would happen (expected changed=true) + assert: + that: + - update_tags_ngw.changed + + # - name: Update the tags - remove and add - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # tags: + # tag_three: '{{ resource_prefix }} Three' + # "Tag Two": 'two {{ resource_prefix }}' + # wait: yes + # register: update_tags_ngw + # check_mode: yes + + # - name: Assert tag update would happen (expected changed=true) - CHECK_MODE + # assert: + # that: + # - update_tags_ngw.changed + + + # ============================================================ + - name: Update the tags add without purge + ec2_vpc_nat_gateway: + if_exist_do_not_create: yes + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + purge_tags: no + tags: + tag_one: '{{ resource_prefix }} One' + wait: yes + register: update_tags_ngw + + - name: Assert tags would be added + assert: + that: + - update_tags_ngw.changed + + # - name: Update the tags add without purge - CHECK_MODE + # ec2_vpc_nat_gateway: + # if_exist_do_not_create: yes + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # purge_tags: no + # tags: + # tag_one: '{{ resource_prefix }} One' + # wait: yes + # register: update_tags_ngw + # check_mode: yes + + # - name: Assert tags would be added - CHECK_MODE + # assert: + # that: + # - update_tags_ngw.changed + + + # ============================================================ + - name: Remove all tags + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + tags: {} + register: delete_tags_ngw + + - name: assert tags would be removed + assert: + that: + - delete_tags_ngw.changed + + # - name: Remove all tags - CHECK_MODE + # ec2_vpc_nat_gateway: + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # tags: {} + # register: delete_tags_ngw + # check_mode: yes + + # - name: assert tags would be removed - CHECK_MODE + # assert: + # that: + # - delete_tags_ngw.changed + + + + # ============================================================ + - name: Update with CamelCase tags + ec2_vpc_nat_gateway: + if_exist_do_not_create: yes + subnet_id: "{{ subnet_id }}" + allocation_id: "{{ allocation_id }}" + purge_tags: no + tags: + "lowercase spaced": 'hello cruel world ❤️' + "Title Case": 'Hello Cruel World ❤️' + CamelCase: 'SimpleCamelCase ❤️' + snake_case: 'simple_snake_case ❤️' + wait: yes + register: update_tags_ngw + + - name: Assert tags would be added + assert: + that: + - update_tags_ngw.changed + - update_tags_ngw.tags["lowercase spaced"] == 'hello cruel world ❤️' + - update_tags_ngw.tags["Title Case"] == 'Hello Cruel World ❤️' + - update_tags_ngw.tags["CamelCase"] == 'SimpleCamelCase ❤️' + - update_tags_ngw.tags["snake_case"] == 'simple_snake_case ❤️' + + + # - name: Update with CamelCase tags - CHECK_MODE + # ec2_vpc_nat_gateway: + # if_exist_do_not_create: yes + # subnet_id: "{{ subnet_id }}" + # allocation_id: "{{ allocation_id }}" + # purge_tags: no + # tags: + # "lowercase spaced": 'hello cruel world ❤️' + # "Title Case": 'Hello Cruel World ❤️' + # CamelCase: 'SimpleCamelCase ❤️' + # snake_case: 'simple_snake_case ❤️' + # wait: yes + # register: update_tags_ngw + + #- name: Assert tags would be added - CHECK_MODE + # assert: + # that: + # - update_tags_ngw.changed + # - update_tags_ngw.tags["lowercase spaced"] == 'hello cruel world ❤️' + # - update_tags_ngw.tags["Title Case"] == 'Hello Cruel World ❤️' + # - update_tags_ngw.tags["CamelCase"] == 'SimpleCamelCase ❤️' + # - update_tags_ngw.tags["snake_case"] == 'simple_snake_case ❤️' + + # ============================================================ + + + always: + - name: Get NAT gateways + ec2_vpc_nat_gateway_info: + filters: + vpc-id: "{{ vpc_id }}" + register: existing_ngws + retries: 10 + until: existing_ngws is not failed + ignore_errors: true + + - name: Tidy up NAT gateway + ec2_vpc_nat_gateway: + subnet_id: "{{ item.subnet_id }}" + nat_gateway_id: "{{ item.nat_gateway_id }}" + #release_eip: yes + state: absent + wait: yes + with_items: "{{ existing_ngws.result }}" + ignore_errors: true + + - name: Delete IGW + ec2_vpc_igw: + vpc_id: "{{ vpc_id }}" + state: absent + ignore_errors: true + + - name: Remove subnet + ec2_vpc_subnet: + state: absent + cidr: "{{ subnet_cidr }}" + vpc_id: "{{ vpc_id }}" + ignore_errors: true + + - name: Ensure EIP is actually released + ec2_eip: + state: absent + device_id: "{{ item.nat_gateway_addresses[0].network_interface_id }}" + in_vpc: yes + with_items: "{{ existing_ngws.result }}" + ignore_errors: yes + + - name: Delete VPC + ec2_vpc_net: + name: "{{ vpc_name }}" + cidr_block: "{{ vpc_cidr }}" + state: absent + purge_cidrs: yes + ignore_errors: yes