From f5c0cac61a4329df703f2d2c91105dd0f1a4cd79 Mon Sep 17 00:00:00 2001 From: jillr Date: Mon, 2 Mar 2020 19:25:18 +0000 Subject: [PATCH 01/31] Initial commit This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/eb75681585a23ea79e642b86a0f8e64e0f40a6d7 --- plugins/modules/ec2_vpc_nat_gateway.py | 1020 +++++++++++++++++ plugins/modules/ec2_vpc_nat_gateway_facts.py | 1 + plugins/modules/ec2_vpc_nat_gateway_info.py | 156 +++ .../targets/ec2_vpc_nat_gateway/aliases | 2 + .../ec2_vpc_nat_gateway/tasks/main.yml | 82 ++ 5 files changed, 1261 insertions(+) create mode 100644 plugins/modules/ec2_vpc_nat_gateway.py create mode 120000 plugins/modules/ec2_vpc_nat_gateway_facts.py create mode 100644 plugins/modules/ec2_vpc_nat_gateway_info.py create mode 100644 tests/integration/targets/ec2_vpc_nat_gateway/aliases create mode 100644 tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py new file mode 100644 index 00000000000..2e35459d438 --- /dev/null +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -0,0 +1,1020 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: ec2_vpc_nat_gateway +short_description: Manage AWS VPC NAT Gateways. +description: + - Ensure the state of AWS VPC NAT Gateways based on their id, allocation and subnet ids. +requirements: [boto3, botocore] +options: + state: + description: + - Ensure NAT Gateway is present or absent. + default: "present" + choices: ["present", "absent"] + type: str + nat_gateway_id: + description: + - The id AWS dynamically allocates to the NAT Gateway on creation. + This is required when the absent option is present. + type: str + subnet_id: + description: + - The id of the subnet to create the NAT Gateway in. This is required + with the present option. + type: str + allocation_id: + description: + - The id of the elastic IP allocation. If this is not passed and the + eip_address is not passed. An EIP is generated for this NAT Gateway. + type: str + eip_address: + description: + - The elastic IP address of the EIP you want attached to this NAT Gateway. + If this is not passed and the allocation_id is not passed, + an EIP is generated for this NAT Gateway. + type: str + if_exist_do_not_create: + description: + - if a NAT Gateway exists already in the subnet_id, then do not create a new one. + required: false + default: false + type: bool + release_eip: + description: + - Deallocate the EIP from the VPC. + - Option is only valid with the absent state. + - You should use this with the wait option. Since you can not release an address while a delete operation is happening. + default: false + type: bool + wait: + description: + - Wait for operation to complete before returning. + default: false + type: bool + wait_timeout: + description: + - How many seconds to wait for an operation to complete before timing out. + default: 320 + type: int + client_token: + description: + - Optional unique token to be used during create to ensure idempotency. + When specifying this option, ensure you specify the eip_address parameter + as well otherwise any subsequent runs will fail. + type: str +author: + - Allen Sanabria (@linuxdynasty) + - Jon Hadfield (@jonhadfield) + - Karen Cheng (@Etherdaemon) +extends_documentation_fragment: +- ansible.amazon.aws +- ansible.amazon.ec2 + +''' + +EXAMPLES = ''' +# Note: These examples do not set authentication details, see the AWS Guide for details. + +- name: Create new nat gateway with client token. + ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + eip_address: 52.1.1.1 + region: ap-southeast-2 + client_token: abcd-12345678 + register: new_nat_gateway + +- name: Create new nat gateway using an allocation-id. + ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + allocation_id: eipalloc-12345678 + region: ap-southeast-2 + register: new_nat_gateway + +- name: Create new nat gateway, using an EIP address and wait for available status. + ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + eip_address: 52.1.1.1 + wait: true + region: ap-southeast-2 + register: new_nat_gateway + +- name: Create new nat gateway and allocate new EIP. + ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + wait: true + region: ap-southeast-2 + register: new_nat_gateway + +- name: Create new nat gateway and allocate new EIP if a nat gateway does not yet exist in the subnet. + ec2_vpc_nat_gateway: + state: present + subnet_id: subnet-12345678 + wait: true + region: ap-southeast-2 + if_exist_do_not_create: true + register: new_nat_gateway + +- name: Delete nat gateway using discovered nat gateways from facts module. + ec2_vpc_nat_gateway: + state: absent + region: ap-southeast-2 + wait: true + nat_gateway_id: "{{ item.NatGatewayId }}" + release_eip: true + register: delete_nat_gateway_result + loop: "{{ gateways_to_remove.result }}" + +- name: Delete nat gateway and wait for deleted status. + ec2_vpc_nat_gateway: + state: absent + nat_gateway_id: nat-12345678 + wait: true + wait_timeout: 500 + region: ap-southeast-2 + +- name: Delete nat gateway and release EIP. + ec2_vpc_nat_gateway: + state: absent + nat_gateway_id: nat-12345678 + release_eip: true + wait: yes + wait_timeout: 300 + region: ap-southeast-2 +''' + +RETURN = ''' +create_time: + description: The ISO 8601 date time format in UTC. + returned: In all cases. + type: str + sample: "2016-03-05T05:19:20.282000+00:00'" +nat_gateway_id: + description: id of the VPC NAT Gateway + returned: In all cases. + type: str + sample: "nat-0d1e3a878585988f8" +subnet_id: + description: id of the Subnet + returned: In all cases. + type: str + sample: "subnet-12345" +state: + description: The current state of the NAT Gateway. + returned: In all cases. + type: str + sample: "available" +vpc_id: + description: id of the VPC. + returned: In all cases. + type: str + sample: "vpc-12345" +nat_gateway_addresses: + description: List of dictionaries containing the public_ip, network_interface_id, private_ip, and allocation_id. + returned: In all cases. + type: str + sample: [ + { + 'public_ip': '52.52.52.52', + 'network_interface_id': 'eni-12345', + 'private_ip': '10.0.0.100', + 'allocation_id': 'eipalloc-12345' + } + ] +''' + +import datetime +import random +import time + +try: + import botocore +except ImportError: + pass # caught by imported HAS_BOTO3 + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, get_aws_connection_info, boto3_conn, + camel_dict_to_snake_dict, HAS_BOTO3) + + +DRY_RUN_GATEWAYS = [ + { + "nat_gateway_id": "nat-123456789", + "subnet_id": "subnet-123456789", + "nat_gateway_addresses": [ + { + "public_ip": "55.55.55.55", + "network_interface_id": "eni-1234567", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-1234567" + } + ], + "state": "available", + "create_time": "2016-03-05T05:19:20.282000+00:00", + "vpc_id": "vpc-12345678" + } +] + +DRY_RUN_ALLOCATION_UNCONVERTED = { + 'Addresses': [ + { + 'PublicIp': '55.55.55.55', + 'Domain': 'vpc', + 'AllocationId': 'eipalloc-1234567' + } + ] +} + +DRY_RUN_MSGS = 'DryRun Mode:' + + +def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, + states=None, check_mode=False): + """Retrieve a list of NAT Gateways + Args: + client (botocore.client.EC2): Boto3 client + + Kwargs: + subnet_id (str): The subnet_id the nat resides in. + nat_gateway_id (str): The Amazon nat id. + states (list): States available (pending, failed, available, deleting, and deleted) + default=None + + Basic Usage: + >>> client = boto3.client('ec2') + >>> subnet_id = 'subnet-12345678' + >>> get_nat_gateways(client, subnet_id) + [ + true, + "", + { + "nat_gateway_id": "nat-123456789", + "subnet_id": "subnet-123456789", + "nat_gateway_addresses": [ + { + "public_ip": "55.55.55.55", + "network_interface_id": "eni-1234567", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-1234567" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-12345678" + } + + Returns: + Tuple (bool, str, list) + """ + params = dict() + err_msg = "" + gateways_retrieved = False + existing_gateways = list() + if not states: + states = ['available', 'pending'] + if nat_gateway_id: + params['NatGatewayIds'] = [nat_gateway_id] + else: + params['Filter'] = [ + { + 'Name': 'subnet-id', + 'Values': [subnet_id] + }, + { + 'Name': 'state', + 'Values': states + } + ] + + try: + if not check_mode: + gateways = client.describe_nat_gateways(**params)['NatGateways'] + if gateways: + for gw in gateways: + existing_gateways.append(camel_dict_to_snake_dict(gw)) + gateways_retrieved = True + else: + gateways_retrieved = True + if nat_gateway_id: + if DRY_RUN_GATEWAYS[0]['nat_gateway_id'] == nat_gateway_id: + existing_gateways = DRY_RUN_GATEWAYS + elif subnet_id: + if DRY_RUN_GATEWAYS[0]['subnet_id'] == subnet_id: + existing_gateways = DRY_RUN_GATEWAYS + err_msg = '{0} Retrieving gateways'.format(DRY_RUN_MSGS) + + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + return gateways_retrieved, err_msg, existing_gateways + + +def wait_for_status(client, wait_timeout, nat_gateway_id, status, + check_mode=False): + """Wait for the NAT Gateway to reach a status + Args: + client (botocore.client.EC2): Boto3 client + wait_timeout (int): Number of seconds to wait, until this timeout is reached. + nat_gateway_id (str): The Amazon nat id. + status (str): The status to wait for. + examples. status=available, status=deleted + + Basic Usage: + >>> client = boto3.client('ec2') + >>> subnet_id = 'subnet-12345678' + >>> allocation_id = 'eipalloc-12345678' + >>> wait_for_status(client, subnet_id, allocation_id) + [ + true, + "", + { + "nat_gateway_id": "nat-123456789", + "subnet_id": "subnet-1234567", + "nat_gateway_addresses": [ + { + "public_ip": "55.55.55.55", + "network_interface_id": "eni-1234567", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-12345678" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-12345677" + } + ] + + Returns: + Tuple (bool, str, dict) + """ + polling_increment_secs = 5 + wait_timeout = time.time() + wait_timeout + status_achieved = False + nat_gateway = dict() + states = ['pending', 'failed', 'available', 'deleting', 'deleted'] + err_msg = "" + + while wait_timeout > time.time(): + try: + gws_retrieved, err_msg, nat_gateways = ( + get_nat_gateways( + client, nat_gateway_id=nat_gateway_id, + states=states, check_mode=check_mode + ) + ) + if gws_retrieved and nat_gateways: + nat_gateway = nat_gateways[0] + if check_mode: + nat_gateway['state'] = status + + if nat_gateway.get('state') == status: + status_achieved = True + break + + elif nat_gateway.get('state') == 'failed': + err_msg = nat_gateway.get('failure_message') + break + + elif nat_gateway.get('state') == 'pending': + if 'failure_message' in nat_gateway: + err_msg = nat_gateway.get('failure_message') + status_achieved = False + break + + else: + time.sleep(polling_increment_secs) + + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + if not status_achieved: + err_msg = "Wait time out reached, while waiting for results" + + return status_achieved, err_msg, nat_gateway + + +def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, + check_mode=False): + """Retrieve all NAT Gateways for a subnet. + Args: + subnet_id (str): The subnet_id the nat resides in. + + Kwargs: + allocation_id (str): The EIP Amazon identifier. + default = None + + Basic Usage: + >>> client = boto3.client('ec2') + >>> subnet_id = 'subnet-1234567' + >>> allocation_id = 'eipalloc-1234567' + >>> gateway_in_subnet_exists(client, subnet_id, allocation_id) + ( + [ + { + "nat_gateway_id": "nat-123456789", + "subnet_id": "subnet-123456789", + "nat_gateway_addresses": [ + { + "public_ip": "55.55.55.55", + "network_interface_id": "eni-1234567", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-1234567" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-1234567" + } + ], + False + ) + + Returns: + Tuple (list, bool) + """ + 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 + ) + ) + if not gws_retrieved: + return gateways, allocation_id_exists + for gw in gws: + for address in gw['nat_gateway_addresses']: + if allocation_id: + if address.get('allocation_id') == allocation_id: + allocation_id_exists = True + gateways.append(gw) + else: + gateways.append(gw) + + return gateways, allocation_id_exists + + +def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): + """Release an EIP from your EIP Pool + Args: + client (botocore.client.EC2): Boto3 client + eip_address (str): The Elastic IP Address of the EIP. + + Kwargs: + check_mode (bool): if set to true, do not run anything and + falsify the results. + + Basic Usage: + >>> client = boto3.client('ec2') + >>> eip_address = '52.87.29.36' + >>> get_eip_allocation_id_by_address(client, eip_address) + 'eipalloc-36014da3' + + Returns: + Tuple (str, str) + """ + params = { + 'PublicIps': [eip_address], + } + allocation_id = None + err_msg = "" + try: + if not check_mode: + allocations = client.describe_addresses(**params)['Addresses'] + if len(allocations) == 1: + allocation = allocations[0] + else: + allocation = None + else: + dry_run_eip = ( + DRY_RUN_ALLOCATION_UNCONVERTED['Addresses'][0]['PublicIp'] + ) + if dry_run_eip == eip_address: + allocation = DRY_RUN_ALLOCATION_UNCONVERTED['Addresses'][0] + else: + allocation = None + if allocation: + if allocation.get('Domain') != 'vpc': + err_msg = ( + "EIP {0} is a non-VPC EIP, please allocate a VPC scoped EIP" + .format(eip_address) + ) + else: + allocation_id = allocation.get('AllocationId') + else: + err_msg = ( + "EIP {0} does not exist".format(eip_address) + ) + + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + return allocation_id, err_msg + + +def allocate_eip_address(client, check_mode=False): + """Release an EIP from your EIP Pool + Args: + client (botocore.client.EC2): Boto3 client + + Kwargs: + check_mode (bool): if set to true, do not run anything and + falsify the results. + + Basic Usage: + >>> client = boto3.client('ec2') + >>> allocate_eip_address(client) + True + + Returns: + Tuple (bool, str) + """ + ip_allocated = False + new_eip = None + err_msg = '' + params = { + 'Domain': 'vpc', + } + try: + if check_mode: + ip_allocated = True + random_numbers = ( + ''.join(str(x) for x in random.sample(range(0, 9), 7)) + ) + new_eip = 'eipalloc-{0}'.format(random_numbers) + else: + new_eip = client.allocate_address(**params)['AllocationId'] + ip_allocated = True + err_msg = 'eipalloc id {0} created'.format(new_eip) + + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + return ip_allocated, err_msg, new_eip + + +def release_address(client, allocation_id, check_mode=False): + """Release an EIP from your EIP Pool + Args: + client (botocore.client.EC2): Boto3 client + allocation_id (str): The eip Amazon identifier. + + Kwargs: + check_mode (bool): if set to true, do not run anything and + falsify the results. + + Basic Usage: + >>> client = boto3.client('ec2') + >>> allocation_id = "eipalloc-123456" + >>> release_address(client, allocation_id) + True + + Returns: + Boolean, string + """ + err_msg = '' + if check_mode: + return True, '' + + ip_released = False + try: + client.describe_addresses(AllocationIds=[allocation_id]) + except botocore.exceptions.ClientError as e: + # IP address likely already released + # Happens with gateway in 'deleted' state that + # still lists associations + return True, str(e) + try: + client.release_address(AllocationId=allocation_id) + ip_released = True + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + return ip_released, err_msg + + +def create(client, subnet_id, allocation_id, client_token=None, + wait=False, wait_timeout=0, if_exist_do_not_create=False, + check_mode=False): + """Create an Amazon NAT Gateway. + Args: + client (botocore.client.EC2): Boto3 client + subnet_id (str): The subnet_id the nat resides in. + allocation_id (str): The eip Amazon identifier. + + Kwargs: + if_exist_do_not_create (bool): if a nat gateway already exists in this + subnet, than do not create another one. + default = False + wait (bool): Wait for the nat to be in the deleted state before returning. + default = False + wait_timeout (int): Number of seconds to wait, until this timeout is reached. + default = 0 + client_token (str): + default = None + + Basic Usage: + >>> client = boto3.client('ec2') + >>> subnet_id = 'subnet-1234567' + >>> allocation_id = 'eipalloc-1234567' + >>> create(client, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True, wait_timeout=500) + [ + true, + "", + { + "nat_gateway_id": "nat-123456789", + "subnet_id": "subnet-1234567", + "nat_gateway_addresses": [ + { + "public_ip": "55.55.55.55", + "network_interface_id": "eni-1234567", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-1234567" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-1234567" + } + ] + + Returns: + Tuple (bool, str, list) + """ + params = { + 'SubnetId': subnet_id, + 'AllocationId': allocation_id + } + request_time = datetime.datetime.utcnow() + changed = False + success = False + token_provided = False + err_msg = "" + + if client_token: + token_provided = True + params['ClientToken'] = client_token + + try: + if not check_mode: + result = camel_dict_to_snake_dict(client.create_nat_gateway(**params)["NatGateway"]) + else: + result = DRY_RUN_GATEWAYS[0] + 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) + if token_provided and (request_time > create_time): + changed = False + elif wait: + success, err_msg, result = ( + wait_for_status( + 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']) + ) + + except botocore.exceptions.ClientError as e: + if "IdempotentParameterMismatch" in e.message: + err_msg = ( + 'NAT Gateway does not support update and token has already been provided: ' + str(e) + ) + else: + err_msg = str(e) + success = False + changed = False + result = None + + return success, changed, err_msg, result + + +def pre_create(client, subnet_id, 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. + Args: + client (botocore.client.EC2): Boto3 client + subnet_id (str): The subnet_id the nat resides in. + + Kwargs: + allocation_id (str): The EIP Amazon identifier. + default = None + eip_address (str): The Elastic IP Address of the EIP. + default = None + if_exist_do_not_create (bool): if a nat gateway already exists in this + subnet, than do not create another one. + default = False + wait (bool): Wait for the nat to be in the deleted state before returning. + default = False + wait_timeout (int): Number of seconds to wait, until this timeout is reached. + default = 0 + client_token (str): + default = None + + Basic Usage: + >>> client = boto3.client('ec2') + >>> subnet_id = 'subnet-w4t12897' + >>> allocation_id = 'eipalloc-36014da3' + >>> pre_create(client, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True, wait_timeout=500) + [ + true, + "", + { + "nat_gateway_id": "nat-03835afb6e31df79b", + "subnet_id": "subnet-w4t12897", + "nat_gateway_addresses": [ + { + "public_ip": "52.87.29.36", + "network_interface_id": "eni-5579742d", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-36014da3" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-w68571b5" + } + ] + + Returns: + Tuple (bool, bool, str, list) + """ + success = False + changed = False + err_msg = "" + 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) + ) + + if len(existing_gateways) > 0 and if_exist_do_not_create: + success = True + changed = False + results = existing_gateways[0] + err_msg = ( + 'NAT Gateway {0} already exists in subnet_id {1}' + .format( + existing_gateways[0]['nat_gateway_id'], subnet_id + ) + ) + return success, changed, err_msg, results + else: + success, err_msg, allocation_id = ( + allocate_eip_address(client, check_mode=check_mode) + ) + if not success: + return success, 'False', err_msg, dict() + + elif eip_address or allocation_id: + if eip_address and not allocation_id: + allocation_id, err_msg = ( + get_eip_allocation_id_by_address( + client, eip_address, check_mode=check_mode + ) + ) + if not allocation_id: + 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): + success = True + changed = False + results = existing_gateways[0] + err_msg = ( + 'NAT Gateway {0} already exists in subnet_id {1}' + .format( + existing_gateways[0]['nat_gateway_id'], subnet_id + ) + ) + return success, changed, err_msg, results + + success, changed, err_msg, results = create( + client, subnet_id, allocation_id, client_token, + wait, wait_timeout, if_exist_do_not_create, check_mode=check_mode + ) + + return success, changed, err_msg, results + + +def remove(client, nat_gateway_id, wait=False, wait_timeout=0, + release_eip=False, check_mode=False): + """Delete an Amazon NAT Gateway. + Args: + client (botocore.client.EC2): Boto3 client + nat_gateway_id (str): The Amazon nat id. + + Kwargs: + wait (bool): Wait for the nat to be in the deleted state before returning. + wait_timeout (int): Number of seconds to wait, until this timeout is reached. + release_eip (bool): Once the nat has been deleted, you can deallocate the eip from the vpc. + + Basic Usage: + >>> client = boto3.client('ec2') + >>> nat_gw_id = 'nat-03835afb6e31df79b' + >>> remove(client, nat_gw_id, wait=True, wait_timeout=500, release_eip=True) + [ + true, + "", + { + "nat_gateway_id": "nat-03835afb6e31df79b", + "subnet_id": "subnet-w4t12897", + "nat_gateway_addresses": [ + { + "public_ip": "52.87.29.36", + "network_interface_id": "eni-5579742d", + "private_ip": "10.0.0.102", + "allocation_id": "eipalloc-36014da3" + } + ], + "state": "deleted", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", + "vpc_id": "vpc-w68571b5" + } + ] + + Returns: + Tuple (bool, str, list) + """ + params = { + 'NatGatewayId': nat_gateway_id + } + success = False + changed = False + err_msg = "" + results = list() + states = ['pending', 'available'] + try: + exist, err_msg, gw = ( + get_nat_gateways( + client, nat_gateway_id=nat_gateway_id, + states=states, check_mode=check_mode + ) + ) + if exist and len(gw) == 1: + results = gw[0] + if not check_mode: + client.delete_nat_gateway(**params) + + allocation_id = ( + results['nat_gateway_addresses'][0]['allocation_id'] + ) + changed = True + success = True + err_msg = ( + 'NAT gateway {0} is in a deleting state. Delete was successful' + .format(nat_gateway_id) + ) + + if wait: + status_achieved, err_msg, results = ( + wait_for_status( + client, wait_timeout, nat_gateway_id, 'deleted', + check_mode=check_mode + ) + ) + if status_achieved: + err_msg = ( + 'NAT gateway {0} was deleted successfully' + .format(nat_gateway_id) + ) + + except botocore.exceptions.ClientError as e: + err_msg = str(e) + + if release_eip: + eip_released, eip_err = ( + release_address(client, allocation_id, check_mode) + ) + if not eip_released: + err_msg = ( + "{0}: Failed to release EIP {1}: {2}" + .format(err_msg, allocation_id, eip_err) + ) + success = False + + return success, changed, err_msg, results + + +def main(): + argument_spec = ec2_argument_spec() + argument_spec.update( + dict( + subnet_id=dict(type='str'), + eip_address=dict(type='str'), + allocation_id=dict(type='str'), + if_exist_do_not_create=dict(type='bool', default=False), + state=dict(default='present', choices=['present', 'absent']), + wait=dict(type='bool', default=False), + wait_timeout=dict(type='int', default=320, required=False), + release_eip=dict(type='bool', default=False), + nat_gateway_id=dict(type='str'), + client_token=dict(type='str'), + ) + ) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=[ + ['allocation_id', 'eip_address'] + ], + required_if=[['state', 'absent', ['nat_gateway_id']], + ['state', 'present', ['subnet_id']]] + ) + + # Validate Requirements + if not HAS_BOTO3: + module.fail_json(msg='botocore/boto3 is required.') + + state = module.params.get('state').lower() + check_mode = module.check_mode + subnet_id = module.params.get('subnet_id') + allocation_id = module.params.get('allocation_id') + eip_address = module.params.get('eip_address') + nat_gateway_id = module.params.get('nat_gateway_id') + wait = module.params.get('wait') + wait_timeout = module.params.get('wait_timeout') + 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') + + try: + region, ec2_url, aws_connect_kwargs = ( + get_aws_connection_info(module, boto3=True) + ) + client = ( + boto3_conn( + module, conn_type='client', resource='ec2', + region=region, endpoint=ec2_url, **aws_connect_kwargs + ) + ) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Boto3 Client Error - " + str(e.msg)) + + changed = False + err_msg = '' + + if state == 'present': + success, changed, err_msg, results = ( + pre_create( + client, subnet_id, allocation_id, eip_address, + if_exist_do_not_create, wait, wait_timeout, + client_token, check_mode=check_mode + ) + ) + else: + success, changed, err_msg, results = ( + remove( + client, nat_gateway_id, wait, wait_timeout, release_eip, + check_mode=check_mode + ) + ) + + if not success: + module.fail_json( + msg=err_msg, success=success, changed=changed + ) + else: + module.exit_json( + msg=err_msg, success=success, changed=changed, **results + ) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py new file mode 120000 index 00000000000..fd969989977 --- /dev/null +++ b/plugins/modules/ec2_vpc_nat_gateway_facts.py @@ -0,0 +1 @@ +ec2_vpc_nat_gateway_info.py \ No newline at end of file diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py new file mode 100644 index 00000000000..b86e4bb8114 --- /dev/null +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -0,0 +1,156 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +module: ec2_vpc_nat_gateway_info +short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. +description: + - Gets various details related to AWS VPC Managed Nat Gateways + - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change. +requirements: [ boto3 ] +options: + nat_gateway_ids: + description: + - List of specific nat gateway IDs to fetch details for. + type: list + elements: str + filters: + description: + - A dict of filters to apply. Each dict item consists of a filter key and a filter value. + See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNatGateways.html) + for possible filters. + type: dict +author: Karen Cheng (@Etherdaemon) +extends_documentation_fragment: +- ansible.amazon.aws +- ansible.amazon.ec2 + +''' + +EXAMPLES = ''' +# Simple example of listing all nat gateways +- name: List all managed nat gateways in ap-southeast-2 + ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + register: all_ngws + +- name: Debugging the result + debug: + msg: "{{ all_ngws.result }}" + +- name: Get details on specific nat gateways + ec2_vpc_nat_gateway_info: + nat_gateway_ids: + - nat-1234567891234567 + - nat-7654321987654321 + region: ap-southeast-2 + register: specific_ngws + +- name: Get all nat gateways with specific filters + ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + filters: + state: ['pending'] + register: pending_ngws + +- name: Get nat gateways with specific filter + ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + filters: + subnet-id: subnet-12345678 + state: ['available'] + register: existing_nat_gateways +''' + +RETURN = ''' +result: + description: The result of the describe, converted to ansible snake case style. + See http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways for the response. + returned: success + type: list +''' + +import json + +try: + import botocore +except ImportError: + pass # will be detected by imported HAS_BOTO3 + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, get_aws_connection_info, boto3_conn, + camel_dict_to_snake_dict, ansible_dict_to_boto3_filter_list, boto3_tag_list_to_ansible_dict, HAS_BOTO3) + + +def date_handler(obj): + return obj.isoformat() if hasattr(obj, 'isoformat') else obj + + +def get_nat_gateways(client, module, nat_gateway_id=None): + params = dict() + nat_gateways = list() + + params['Filter'] = ansible_dict_to_boto3_filter_list(module.params.get('filters')) + params['NatGatewayIds'] = module.params.get('nat_gateway_ids') + + try: + result = json.loads(json.dumps(client.describe_nat_gateways(**params), default=date_handler)) + except Exception as e: + module.fail_json(msg=str(e.message)) + + for gateway in result['NatGateways']: + # Turn the boto3 result into ansible_friendly_snaked_names + converted_gateway = camel_dict_to_snake_dict(gateway) + if 'tags' in converted_gateway: + # Turn the boto3 result into ansible friendly tag dictionary + converted_gateway['tags'] = boto3_tag_list_to_ansible_dict(converted_gateway['tags']) + + nat_gateways.append(converted_gateway) + + return nat_gateways + + +def main(): + argument_spec = ec2_argument_spec() + argument_spec.update( + dict( + filters=dict(default={}, type='dict'), + nat_gateway_ids=dict(default=[], type='list'), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + if module._name == 'ec2_vpc_nat_gateway_facts': + module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", version='2.13') + + # Validate Requirements + if not HAS_BOTO3: + module.fail_json(msg='botocore/boto3 is required.') + + try: + region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) + if region: + connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_params) + else: + module.fail_json(msg="region must be specified") + except botocore.exceptions.NoCredentialsError as e: + module.fail_json(msg=str(e)) + + results = get_nat_gateways(connection, module) + + module.exit_json(result=results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases new file mode 100644 index 00000000000..6e3860bee23 --- /dev/null +++ b/tests/integration/targets/ec2_vpc_nat_gateway/aliases @@ -0,0 +1,2 @@ +cloud/aws +shippable/aws/group2 diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml new file mode 100644 index 00000000000..7cb7e986e0a --- /dev/null +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -0,0 +1,82 @@ +# The tests for this module are incomplete. +# The tests below were migrated from unit tests. +# 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 From cbb29a66fa31688af7f5a6849b68d317b5fe07e7 Mon Sep 17 00:00:00 2001 From: jillr Date: Tue, 3 Mar 2020 19:43:21 +0000 Subject: [PATCH 02/31] migration test cleanup This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/13b104b912784bb31a0bff23eed4c27b0f5e0283 --- plugins/modules/ec2_vpc_nat_gateway.py | 8 ++++++-- plugins/modules/ec2_vpc_nat_gateway_info.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 2e35459d438..5cb3236885e 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -209,8 +209,12 @@ pass # caught by imported HAS_BOTO3 from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, get_aws_connection_info, boto3_conn, - camel_dict_to_snake_dict, HAS_BOTO3) +from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, + get_aws_connection_info, + boto3_conn, + camel_dict_to_snake_dict, + HAS_BOTO3, + ) DRY_RUN_GATEWAYS = [ diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index b86e4bb8114..bd1dde7ce7f 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -88,8 +88,14 @@ pass # will be detected by imported HAS_BOTO3 from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, get_aws_connection_info, boto3_conn, - camel_dict_to_snake_dict, ansible_dict_to_boto3_filter_list, boto3_tag_list_to_ansible_dict, HAS_BOTO3) +from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, + get_aws_connection_info, + boto3_conn, + camel_dict_to_snake_dict, + ansible_dict_to_boto3_filter_list, + boto3_tag_list_to_ansible_dict, + HAS_BOTO3, + ) def date_handler(obj): From 77dd65367faf0b9f373d2ee2c5006d93d7b56685 Mon Sep 17 00:00:00 2001 From: Jill R <4121322+jillr@users.noreply.github.com> Date: Wed, 25 Mar 2020 15:39:40 -0700 Subject: [PATCH 03/31] Rename collection (#12) * Rename core collection Rename references to ansible.amazon to amazon.aws. * Rename community.amazon to community.aws Fix pep8 line lengths for rewritten amazon.aws imports * Missed a path in shippable.sh * Dependency repos moved This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/235c5db571cc45db5839476c94356c9b91e1f228 --- plugins/modules/ec2_vpc_nat_gateway.py | 16 ++++++++-------- plugins/modules/ec2_vpc_nat_gateway_info.py | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 5cb3236885e..09fc70de335 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -80,8 +80,8 @@ - Jon Hadfield (@jonhadfield) - Karen Cheng (@Etherdaemon) extends_documentation_fragment: -- ansible.amazon.aws -- ansible.amazon.ec2 +- amazon.aws.aws +- amazon.aws.ec2 ''' @@ -209,12 +209,12 @@ pass # caught by imported HAS_BOTO3 from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, - get_aws_connection_info, - boto3_conn, - camel_dict_to_snake_dict, - HAS_BOTO3, - ) +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ec2_argument_spec, + get_aws_connection_info, + boto3_conn, + camel_dict_to_snake_dict, + HAS_BOTO3, + ) DRY_RUN_GATEWAYS = [ diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index bd1dde7ce7f..a4891391854 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -32,8 +32,8 @@ type: dict author: Karen Cheng (@Etherdaemon) extends_documentation_fragment: -- ansible.amazon.aws -- ansible.amazon.ec2 +- amazon.aws.aws +- amazon.aws.ec2 ''' @@ -88,14 +88,14 @@ pass # will be detected by imported HAS_BOTO3 from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.amazon.plugins.module_utils.ec2 import (ec2_argument_spec, - get_aws_connection_info, - boto3_conn, - camel_dict_to_snake_dict, - ansible_dict_to_boto3_filter_list, - boto3_tag_list_to_ansible_dict, - HAS_BOTO3, - ) +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ec2_argument_spec, + get_aws_connection_info, + boto3_conn, + camel_dict_to_snake_dict, + ansible_dict_to_boto3_filter_list, + boto3_tag_list_to_ansible_dict, + HAS_BOTO3, + ) def date_handler(obj): From 1f3a8c6a34cf98dc98b168cb99f0096c23557180 Mon Sep 17 00:00:00 2001 From: Jill R <4121322+jillr@users.noreply.github.com> Date: Tue, 19 May 2020 16:06:12 -0700 Subject: [PATCH 04/31] Remove METADATA and cleanup galaxy.yml (#70) * Remove ANSIBLE_METADATA entirely, see ansible/ansible/pull/69454. Remove `license` field from galaxy.yml, in favor of `license_file`. This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/05672a64e2362cc2d865b5af6a57da6bc3cd08e3 --- plugins/modules/ec2_vpc_nat_gateway.py | 5 ----- plugins/modules/ec2_vpc_nat_gateway_info.py | 5 ----- 2 files changed, 10 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 09fc70de335..d8ee5167b67 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -6,11 +6,6 @@ __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - DOCUMENTATION = ''' --- module: ec2_vpc_nat_gateway diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index a4891391854..a4e7ac6db99 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -6,11 +6,6 @@ __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - DOCUMENTATION = ''' module: ec2_vpc_nat_gateway_info short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. From a1a6c235fc37f06c3bcb70eae8e49c6c6c32aae2 Mon Sep 17 00:00:00 2001 From: Jill R <4121322+jillr@users.noreply.github.com> Date: Tue, 16 Jun 2020 11:23:52 -0700 Subject: [PATCH 05/31] Collections related fixes for CI (#96) * Update module deprecations Switch version to `removed_at_date` * Don't install amazon.aws from galaxy We've been using galaxy to install amazon.aws in shippable, but that doesn't really work if we aren't publising faster. Get that collection from git so it is most up to date. * We need to declare python test deps now * missed a python dep This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/7cd211e9383db26bc2aa4cc06e657cf60ed0acc0 --- plugins/modules/ec2_vpc_nat_gateway_info.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index a4e7ac6db99..85f96cc7340 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -133,7 +133,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'ec2_vpc_nat_gateway_facts': - module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", version='2.13') + module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", + date='2021-12-01', collection_name='community.aws') # Validate Requirements if not HAS_BOTO3: From d6862af7d2d623529271dbd66b40dff0bca7e16f Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 17 Jun 2020 01:24:54 +0530 Subject: [PATCH 06/31] Update Examples with FQCN (#67) Updated module examples with FQCN Signed-off-by: Abhijeet Kasurde This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/98173aefbbceed7fc0d9db62687b73f96a55a999 --- plugins/modules/ec2_vpc_nat_gateway.py | 16 ++++++++-------- plugins/modules/ec2_vpc_nat_gateway_info.py | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index d8ee5167b67..306c8ac49c4 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -84,7 +84,7 @@ # Note: These examples do not set authentication details, see the AWS Guide for details. - name: Create new nat gateway with client token. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 eip_address: 52.1.1.1 @@ -93,7 +93,7 @@ register: new_nat_gateway - name: Create new nat gateway using an allocation-id. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 allocation_id: eipalloc-12345678 @@ -101,7 +101,7 @@ register: new_nat_gateway - name: Create new nat gateway, using an EIP address and wait for available status. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 eip_address: 52.1.1.1 @@ -110,7 +110,7 @@ register: new_nat_gateway - name: Create new nat gateway and allocate new EIP. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 wait: true @@ -118,7 +118,7 @@ register: new_nat_gateway - name: Create new nat gateway and allocate new EIP if a nat gateway does not yet exist in the subnet. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 wait: true @@ -127,7 +127,7 @@ register: new_nat_gateway - name: Delete nat gateway using discovered nat gateways from facts module. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: absent region: ap-southeast-2 wait: true @@ -137,7 +137,7 @@ loop: "{{ gateways_to_remove.result }}" - name: Delete nat gateway and wait for deleted status. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: absent nat_gateway_id: nat-12345678 wait: true @@ -145,7 +145,7 @@ region: ap-southeast-2 - name: Delete nat gateway and release EIP. - ec2_vpc_nat_gateway: + community.aws.ec2_vpc_nat_gateway: state: absent nat_gateway_id: nat-12345678 release_eip: true diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 85f96cc7340..83fb9b0f182 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -35,7 +35,7 @@ EXAMPLES = ''' # Simple example of listing all nat gateways - name: List all managed nat gateways in ap-southeast-2 - ec2_vpc_nat_gateway_info: + community.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 register: all_ngws @@ -44,7 +44,7 @@ msg: "{{ all_ngws.result }}" - name: Get details on specific nat gateways - ec2_vpc_nat_gateway_info: + community.aws.ec2_vpc_nat_gateway_info: nat_gateway_ids: - nat-1234567891234567 - nat-7654321987654321 @@ -52,14 +52,14 @@ register: specific_ngws - name: Get all nat gateways with specific filters - ec2_vpc_nat_gateway_info: + community.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 filters: state: ['pending'] register: pending_ngws - name: Get nat gateways with specific filter - ec2_vpc_nat_gateway_info: + community.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 filters: subnet-id: subnet-12345678 From eb1ddac0e2bc8d7020b121980c58e73222b696da Mon Sep 17 00:00:00 2001 From: Jill R <4121322+jillr@users.noreply.github.com> Date: Wed, 17 Jun 2020 09:31:32 -0700 Subject: [PATCH 07/31] Update docs (#99) * Update docs Remove .git from repo url so links in readme will generate correctly Add required ansible version Run latest version of add_docs.py Add version_added string to modules * galaxy.yml was missing authors This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/96ee268e5267f5b12c3d59892bc1279f75aa3135 --- plugins/modules/ec2_vpc_nat_gateway.py | 1 + plugins/modules/ec2_vpc_nat_gateway_info.py | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 306c8ac49c4..4272dc648c4 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -9,6 +9,7 @@ DOCUMENTATION = ''' --- module: ec2_vpc_nat_gateway +version_added: 1.0.0 short_description: Manage AWS VPC NAT Gateways. description: - Ensure the state of AWS VPC NAT Gateways based on their id, allocation and subnet ids. diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 83fb9b0f182..b734721b5ea 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -9,6 +9,7 @@ DOCUMENTATION = ''' module: ec2_vpc_nat_gateway_info short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. +version_added: 1.0.0 description: - Gets various details related to AWS VPC Managed Nat Gateways - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change. From 3f4a55f60dbc5a8b701621e2c7b88922a3b929d2 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 16 Jul 2020 01:31:41 +0530 Subject: [PATCH 08/31] Docs: sanity fixes (#133) Signed-off-by: Abhijeet Kasurde This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/059cf9efc95bb976de21ab4f8e4d9ddd001983fc --- plugins/modules/ec2_vpc_nat_gateway_info.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index b734721b5ea..bb164a2b50b 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -6,7 +6,7 @@ __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: ec2_vpc_nat_gateway_info short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. version_added: 1.0.0 @@ -33,7 +33,7 @@ ''' -EXAMPLES = ''' +EXAMPLES = r''' # Simple example of listing all nat gateways - name: List all managed nat gateways in ap-southeast-2 community.aws.ec2_vpc_nat_gateway_info: @@ -68,7 +68,7 @@ register: existing_nat_gateways ''' -RETURN = ''' +RETURN = r''' result: description: The result of the describe, converted to ansible snake case style. See http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways for the response. @@ -127,7 +127,7 @@ def main(): argument_spec.update( dict( filters=dict(default={}, type='dict'), - nat_gateway_ids=dict(default=[], type='list'), + nat_gateway_ids=dict(default=[], type='list', elements='str'), ) ) From ea6b0311dd76238d06022441cf700ca057ca2584 Mon Sep 17 00:00:00 2001 From: Andrew Klychkov Date: Fri, 17 Jul 2020 21:10:09 +0300 Subject: [PATCH 09/31] aws modules: fix examples to use FQCN for builtin modules/plugins (#144) This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/92bebdd5ab3019bbdeee55e8a69c9d903deeac49 --- plugins/modules/ec2_vpc_nat_gateway_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index bb164a2b50b..f076d38a833 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -41,7 +41,7 @@ register: all_ngws - name: Debugging the result - debug: + ansible.builtin.debug: msg: "{{ all_ngws.result }}" - name: Get details on specific nat gateways From bc199cf879504f11d8adc69d738a2104b87d6215 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Wed, 12 Aug 2020 13:06:35 +0200 Subject: [PATCH 10/31] Bulk migration to AnsibleAWSModule (#173) * Update comments to reference AnsibleAWSModule rather than AnsibleModule * Bulk re-order imports and split onto one from import per-line. * Add AnsibleAWSModule imports * Migrate boto 2 based modules to AnsibleAWSModule * Move boto3-only modules over to AnsibleAWSModule * Remove extra ec2_argument_spec calls - not needed now we're using AnsibleAWSModule * Remove most HAS_BOTO3 code, it's handled by AnsibleAWSModule * Handle missing Boto 2 consistently (HAS_BOTO) * Remove AnsibleModule imports * Changelog fragment This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/818c6d2faa046974a9bdfa9346122d11e5bef3b1 --- plugins/modules/ec2_vpc_nat_gateway.py | 46 ++++++++------------- plugins/modules/ec2_vpc_nat_gateway_info.py | 34 ++++++--------- 2 files changed, 30 insertions(+), 50 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 4272dc648c4..2216ffe2276 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -202,15 +202,12 @@ try: import botocore except ImportError: - pass # caught by imported HAS_BOTO3 + pass # Handled by AnsibleAWSModule -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ec2_argument_spec, - get_aws_connection_info, - boto3_conn, - camel_dict_to_snake_dict, - HAS_BOTO3, - ) +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict DRY_RUN_GATEWAYS = [ @@ -933,35 +930,28 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, def main(): - argument_spec = ec2_argument_spec() - argument_spec.update( - dict( - subnet_id=dict(type='str'), - eip_address=dict(type='str'), - allocation_id=dict(type='str'), - if_exist_do_not_create=dict(type='bool', default=False), - state=dict(default='present', choices=['present', 'absent']), - wait=dict(type='bool', default=False), - wait_timeout=dict(type='int', default=320, required=False), - release_eip=dict(type='bool', default=False), - nat_gateway_id=dict(type='str'), - client_token=dict(type='str'), - ) + argument_spec = dict( + subnet_id=dict(type='str'), + eip_address=dict(type='str'), + allocation_id=dict(type='str'), + if_exist_do_not_create=dict(type='bool', default=False), + state=dict(default='present', choices=['present', 'absent']), + wait=dict(type='bool', default=False), + wait_timeout=dict(type='int', default=320, required=False), + release_eip=dict(type='bool', default=False), + nat_gateway_id=dict(type='str'), + client_token=dict(type='str'), ) - module = AnsibleModule( + module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[ ['allocation_id', 'eip_address'] ], required_if=[['state', 'absent', ['nat_gateway_id']], - ['state', 'present', ['subnet_id']]] + ['state', 'present', ['subnet_id']]], ) - # Validate Requirements - if not HAS_BOTO3: - module.fail_json(msg='botocore/boto3 is required.') - state = module.params.get('state').lower() check_mode = module.check_mode subnet_id = module.params.get('subnet_id') diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index f076d38a833..7f49c708857 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -81,17 +81,14 @@ try: import botocore except ImportError: - pass # will be detected by imported HAS_BOTO3 + pass # Handled by AnsibleAWSModule -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ec2_argument_spec, - get_aws_connection_info, - boto3_conn, - camel_dict_to_snake_dict, - ansible_dict_to_boto3_filter_list, - boto3_tag_list_to_ansible_dict, - HAS_BOTO3, - ) +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn +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 boto3_tag_list_to_ansible_dict def date_handler(obj): @@ -123,24 +120,17 @@ def get_nat_gateways(client, module, nat_gateway_id=None): def main(): - argument_spec = ec2_argument_spec() - argument_spec.update( - dict( - filters=dict(default={}, type='dict'), - nat_gateway_ids=dict(default=[], type='list', elements='str'), - ) + argument_spec = dict( + filters=dict(default={}, type='dict'), + nat_gateway_ids=dict(default=[], type='list', elements='str'), ) - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) + module = AnsibleAWSModule(argument_spec=argument_spec, + supports_check_mode=True,) if module._name == 'ec2_vpc_nat_gateway_facts': module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", date='2021-12-01', collection_name='community.aws') - # Validate Requirements - if not HAS_BOTO3: - module.fail_json(msg='botocore/boto3 is required.') - try: region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) if region: From 3f19de9a11c9aff3d12e2165bef968afc472b951 Mon Sep 17 00:00:00 2001 From: Vincent Vinet Date: Sat, 15 Aug 2020 09:11:59 -0400 Subject: [PATCH 11/31] =?UTF-8?q?Python=203=20compatibility=20error=20hand?= =?UTF-8?q?ling:=20use=20to=5Fnative(e)=20instead=20of=20str(e)=20or=20e.m?= =?UTF-8?q?e=E2=80=A6=20(#26)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Py3 compat error handling: use to_native(e) instead of str(e) or e.message * PR comment changes, use fail_json_aws and is_boto3_error_code This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/ffe14f95186399dc080019554035021015765872 --- plugins/modules/ec2_vpc_nat_gateway.py | 18 +++++++++++------- plugins/modules/ec2_vpc_nat_gateway_info.py | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 2216ffe2276..37dd9160084 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -204,7 +204,9 @@ except ImportError: pass # Handled by AnsibleAWSModule +from ansible.module_utils._text import to_native 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 get_aws_connection_info from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -698,13 +700,15 @@ def create(client, subnet_id, allocation_id, client_token=None, 'NAT gateway {0} created'.format(result['nat_gateway_id']) ) - except botocore.exceptions.ClientError as e: - if "IdempotentParameterMismatch" in e.message: - err_msg = ( - 'NAT Gateway does not support update and token has already been provided: ' + str(e) - ) - else: - err_msg = str(e) + except is_boto3_error_code('IdempotentParameterMismatch'): + err_msg = ( + 'NAT Gateway does not support update and token has already been provided: ' + err_msg + ) + success = False + changed = False + result = None + except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except + err_msg = to_native(e) success = False changed = False result = None diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 7f49c708857..9ebeb63fcbb 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -83,6 +83,7 @@ except ImportError: pass # Handled by AnsibleAWSModule +from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn @@ -105,7 +106,7 @@ def get_nat_gateways(client, module, nat_gateway_id=None): try: result = json.loads(json.dumps(client.describe_nat_gateways(**params), default=date_handler)) except Exception as e: - module.fail_json(msg=str(e.message)) + module.fail_json(msg=to_native(e)) for gateway in result['NatGateways']: # Turn the boto3 result into ansible_friendly_snaked_names From 6bcad7fc45d344414c25fa0115379a8a115b5ea3 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Wed, 26 Aug 2020 11:35:32 +0200 Subject: [PATCH 12/31] Cleanup: Bulk Migration from boto3_conn to module.client() (#188) * Migrate from boto3_conn to module.client * Simplify error handling when creating connections * Simplify Region handling * Remove unused imports * Changelog This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/6bdf00d2198927bdaa119ae76ddd379a8b6eeb3d --- plugins/modules/ec2_vpc_nat_gateway.py | 16 +++------------- plugins/modules/ec2_vpc_nat_gateway_info.py | 12 +++--------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 37dd9160084..9072a8e32b6 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -207,8 +207,6 @@ from ansible.module_utils._text import to_native 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 get_aws_connection_info -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict @@ -969,17 +967,9 @@ def main(): if_exist_do_not_create = module.params.get('if_exist_do_not_create') try: - region, ec2_url, aws_connect_kwargs = ( - get_aws_connection_info(module, boto3=True) - ) - client = ( - boto3_conn( - module, conn_type='client', resource='ec2', - region=region, endpoint=ec2_url, **aws_connect_kwargs - ) - ) - except botocore.exceptions.ClientError as e: - module.fail_json(msg="Boto3 Client Error - " + str(e.msg)) + client = module.client('ec2') + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg='Failed to connect to AWS') changed = False err_msg = '' diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 9ebeb63fcbb..97816c72362 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -85,8 +85,6 @@ from ansible.module_utils._text import to_native from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn 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 boto3_tag_list_to_ansible_dict @@ -133,13 +131,9 @@ def main(): date='2021-12-01', collection_name='community.aws') try: - region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) - if region: - connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_params) - else: - module.fail_json(msg="region must be specified") - except botocore.exceptions.NoCredentialsError as e: - module.fail_json(msg=str(e)) + connection = module.client('ec2') + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg='Failed to connect to AWS') results = get_nat_gateways(connection, module) From 3b7728ed71360beddee411f67027ec385f289cab Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Mon, 1 Feb 2021 09:21:05 +0100 Subject: [PATCH 13/31] Tags feature: support tags specification for NAT gateway (#345) (#372) * 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 Co-authored-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/b7afd183d03ba23abb63bb371b51b788f295156b --- 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 From 59133397e6b2396c79d7702f63bf94f9ff875a19 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 11 Feb 2021 19:32:05 +0100 Subject: [PATCH 14/31] Remove ec2_vpc_nat_gateway unit tests (#407) * Remove ec2_vpc_nat_gateway unit tests * update comments in ec2_vpc_nat_gateway integration tests - they're not based on the hard coded check_mode results any more This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/701153a6592739ec83db85284f4e7649444e61f9 --- .../ec2_vpc_nat_gateway/tasks/main.yml | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) 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 2b411340149..36f035c81d1 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -1,19 +1,14 @@ -# The tests for this module are incomplete. -# The tests below were migrated from unit tests. -# 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. - --- # ============================================================ # 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 +# `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`). +# `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 @@ -26,8 +21,8 @@ collections: - amazon.aws - block: - + block: + # ============================================================ - name: Create a VPC ec2_vpc_net: @@ -52,7 +47,7 @@ reuse_existing_ip_allowed: true tag_name: FREE register: eip_result - + - name: Assert success assert: that: @@ -62,7 +57,7 @@ set_fact: eip_address: "{{ eip_result.public_ip }}" allocation_id: "{{ eip_result.allocation_id }}" - + # ============================================================ - name: Create subnet and associate to the VPC @@ -80,7 +75,7 @@ - name: "set fact: VPC subnet ID" set_fact: subnet_id: "{{ subnet_result.subnet.id }}" - + # ============================================================ - name: Search for NAT gateways by subnet - no matches @@ -91,12 +86,12 @@ 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 + - (existing_ngws.result|length) == 0 @@ -105,7 +100,7 @@ ec2_vpc_igw: vpc_id: "{{ vpc_id }}" register: create_igw - + - name: Assert success assert: that: @@ -121,7 +116,7 @@ register: create_ngw retries: 10 until: create_ngw is not failed - + - name: Assert creation happened (expected changed=true) assert: that: @@ -131,7 +126,7 @@ 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 }}" @@ -159,7 +154,7 @@ 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 }}" @@ -167,7 +162,7 @@ # wait: yes # register: create_ngw # check_mode: yes - + # - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE # assert: # that: @@ -175,7 +170,7 @@ # ============================================================ - #- name: Create new NAT gateway with eip address + #- name: Create new NAT gateway with eip address # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" # eip_address: "{{ eip_address }}" @@ -186,7 +181,7 @@ # assert: # that: # - create_ngw.changed - + # - name: Create new nat gateway with eip address - CHECK_MODE # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" @@ -242,7 +237,7 @@ 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 @@ -257,7 +252,7 @@ # - not create_ngw.changed - # ============================================================ + # ============================================================ - name: Delete NAT gateway ec2_vpc_nat_gateway: nat_gateway_id: "{{ nat_gateway_id }}" @@ -271,7 +266,7 @@ assert: that: - delete_nat_gateway.changed - + # - name: Delete NAT gateway - CHECK_MODE # ec2_vpc_nat_gateway: # nat_gateway_id: "{{ nat_gateway_id }}" @@ -332,8 +327,8 @@ - name: assert tag update would do nothing (expected changed=false) assert: that: - - not update_tags_ngw.changed - + - not update_tags_ngw.changed + # - name: Update the tags (no change) - CHECK_MODE # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" @@ -366,7 +361,7 @@ assert: that: - update_tags_ngw.changed - + # - name: Update the tags - remove and add - CHECK_MODE # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" @@ -431,7 +426,7 @@ assert: that: - delete_tags_ngw.changed - + # - name: Remove all tags - CHECK_MODE # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" @@ -445,8 +440,8 @@ # that: # - delete_tags_ngw.changed - - + + # ============================================================ - name: Update with CamelCase tags ec2_vpc_nat_gateway: @@ -496,8 +491,8 @@ # - update_tags_ngw.tags["snake_case"] == 'simple_snake_case ❤️' # ============================================================ - - + + always: - name: Get NAT gateways ec2_vpc_nat_gateway_info: @@ -507,7 +502,7 @@ 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 }}" @@ -517,19 +512,19 @@ 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 - + ignore_errors: true + - name: Remove subnet ec2_vpc_subnet: state: absent cidr: "{{ subnet_cidr }}" vpc_id: "{{ vpc_id }}" - ignore_errors: true + ignore_errors: true - name: Ensure EIP is actually released ec2_eip: From e46abacd3d7cd7a68afb7b8f79ffb8866a3b039e Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Sat, 20 Feb 2021 19:20:44 +0100 Subject: [PATCH 15/31] Mark the ec2_vpc_nat_gateway integration tests 'unstable' (#429) This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/cd1430d5e0d50848ad423730d92c878e5cb8c673 --- tests/integration/targets/ec2_vpc_nat_gateway/aliases | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases index 6e3860bee23..269c6f5f0a5 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/aliases +++ b/tests/integration/targets/ec2_vpc_nat_gateway/aliases @@ -1,2 +1,5 @@ +# https://github.com/ansible-collections/community.aws/issues/428 +unstable + cloud/aws shippable/aws/group2 From 3beb635dbe2a94dc4d5bf30b014059537da6865a Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Tue, 23 Feb 2021 14:35:02 +0100 Subject: [PATCH 16/31] improve ec2_vpc_nat_gateway stability (#427) * attempt to add more information when failures occur * Use pagination and add more retry wrappers * Mark ec2_vpc_nat_gateway stable again. Using paginator and retries seems to have fixed things * Add changelog This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/38be7f997b8b844aaa27e62d5d42b70a790fa4c3 --- plugins/modules/ec2_vpc_nat_gateway.py | 29 ++++++++++++++----- .../targets/ec2_vpc_nat_gateway/aliases | 3 -- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index c4e3cbfd797..0fdd6c96b6d 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -278,6 +278,18 @@ DRY_RUN_MSGS = 'DryRun Mode:' +@AWSRetry.jittered_backoff(retries=10) +def _describe_addresses(client, **params): + paginator = client.get_paginator('describe_addresses') + return paginator.paginate(**params).build_full_result()['Addresses'] + + +@AWSRetry.jittered_backoff(retries=10) +def _describe_nat_gateways(client, **params): + paginator = client.get_paginator('describe_nat_gateways') + return paginator.paginate(**params).build_full_result()['NatGateways'] + + def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, states=None, check_mode=False): """Retrieve a list of NAT Gateways @@ -339,7 +351,7 @@ def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, try: if not check_mode: - gateways = client.describe_nat_gateways(**params)['NatGateways'] + gateways = _describe_nat_gateways(client, **params) if gateways: for gw in gateways: existing_gateways.append(camel_dict_to_snake_dict(gw)) @@ -534,7 +546,7 @@ def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): err_msg = "" try: if not check_mode: - allocations = client.describe_addresses(**params)['Addresses'] + allocations = _describe_addresses(client, **params) if len(allocations) == 1: allocation = allocations[0] else: @@ -597,7 +609,7 @@ def allocate_eip_address(client, check_mode=False): ) new_eip = 'eipalloc-{0}'.format(random_numbers) else: - new_eip = client.allocate_address(**params)['AllocationId'] + new_eip = client.allocate_address(aws_retry=True, **params)['AllocationId'] ip_allocated = True err_msg = 'eipalloc id {0} created'.format(new_eip) @@ -632,14 +644,14 @@ def release_address(client, allocation_id, check_mode=False): ip_released = False try: - client.describe_addresses(AllocationIds=[allocation_id]) + _describe_addresses(client, aws_retry=True, AllocationIds=[allocation_id]) except botocore.exceptions.ClientError as e: # IP address likely already released # Happens with gateway in 'deleted' state that # still lists associations return True, str(e) try: - client.release_address(AllocationId=allocation_id) + client.release_address(aws_retry=True, AllocationId=allocation_id) ip_released = True except botocore.exceptions.ClientError as e: err_msg = str(e) @@ -712,7 +724,7 @@ def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_to try: if not check_mode: - result = camel_dict_to_snake_dict(client.create_nat_gateway(**params)["NatGateway"]) + result = camel_dict_to_snake_dict(client.create_nat_gateway(aws_retry=True, **params)["NatGateway"]) else: result = DRY_RUN_GATEWAYS[0] result['create_time'] = datetime.datetime.utcnow() @@ -939,7 +951,7 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, if exist and len(gw) == 1: results = gw[0] if not check_mode: - client.delete_nat_gateway(**params) + client.delete_nat_gateway(aws_retry=True, **params) allocation_id = ( results['nat_gateway_addresses'][0]['allocation_id'] @@ -1102,8 +1114,9 @@ def main(): ) if not success: + results = results or {} module.fail_json( - msg=err_msg, success=success, changed=changed + msg=err_msg, success=success, changed=changed, **results ) else: module.exit_json( diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases index 269c6f5f0a5..6e3860bee23 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/aliases +++ b/tests/integration/targets/ec2_vpc_nat_gateway/aliases @@ -1,5 +1,2 @@ -# https://github.com/ansible-collections/community.aws/issues/428 -unstable - cloud/aws shippable/aws/group2 From d76dcdcac7a7d44a300ac8043af2e590de89a5ee Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Wed, 24 Feb 2021 17:51:05 +0100 Subject: [PATCH 17/31] ec2_vpc_nat_gateway: increase integration tests coverage (#387) * NAT gateway: increase integration tests coverage * Add additional integration tests for ec2_vpc_nat_gateway_info and ec2_vpc_nat_gatewy modules * Add ec2_vpc_nat_gateway_info in aliases * Fix NAT gateway search Signed-off-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/fbfc351e38ec858d6e8c079670b1c9ce00af33fc --- .../targets/ec2_vpc_nat_gateway/aliases | 1 + .../ec2_vpc_nat_gateway/tasks/main.yml | 539 +++++++++++++++++- 2 files changed, 520 insertions(+), 20 deletions(-) diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases index 6e3860bee23..e2557d59343 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/aliases +++ b/tests/integration/targets/ec2_vpc_nat_gateway/aliases @@ -1,2 +1,3 @@ cloud/aws shippable/aws/group2 +ec2_vpc_nat_gateway_info 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 36f035c81d1..f43a3ece55c 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -52,6 +52,7 @@ assert: that: - eip_result is successful + - 'eip_result.allocation_id.startswith("eipalloc-")' - name: "set fact: EIP allocation ID and EIP public IP" set_fact: @@ -71,6 +72,10 @@ assert: that: - subnet_result is successful + - subnet_result.subnet.id.startswith("subnet-") + - subnet_result.subnet.cidr_block == subnet_cidr + - subnet_result.subnet.state == 'available' + - subnet_result.subnet.vpc_id == vpc_id - name: "set fact: VPC subnet ID" set_fact: @@ -93,6 +98,19 @@ - existing_ngws is successful - (existing_ngws.result|length) == 0 + # - name: Search for NAT gateways by subnet (no matches) - CHECK_MODE + # ec2_vpc_nat_gateway_info: + # filters: + # subnet-id: "{{ subnet_id }}" + # state: ['available'] + # register: existing_ngws + # check_mode: yes + + # - name: Assert no NAT gateway found - CHECK_MODE + # assert: + # that: + # - existing_ngws is successful + # - (existing_ngws.result|length) == 0 # ============================================================ @@ -105,6 +123,9 @@ assert: that: - create_igw is successful + - create_igw.gateway_id.startswith("igw-") + - create_igw.vpc_id == vpc_id + - '"gateway_id" in create_igw' # ============================================================ @@ -121,24 +142,105 @@ assert: that: - create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id - 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: 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 + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id + + + # ============================================================ + - name: Get NAT gateway with specific filters (state and subnet) + ec2_vpc_nat_gateway_info: + filters: + subnet-id: "{{ subnet_id }}" + state: ['available'] + register: avalaible_ngws + retries: 10 + until: avalaible_ngws is not failed + + - name: Assert success + assert: + that: + - avalaible_ngws is successful + - avalaible_ngws.result | length == 1 + - '"create_time" in first_ngw' + - '"nat_gateway_addresses" in first_ngw' + - '"nat_gateway_id" in first_ngw' + - first_ngw.nat_gateway_id == nat_gateway_id + - '"state" in first_ngw' + - first_ngw.state == 'available' + - '"subnet_id" in first_ngw' + - first_ngw.subnet_id == subnet_id + - '"tags" in first_ngw' + - '"vpc_id" in first_ngw' + - first_ngw.vpc_id == vpc_id + vars: + first_ngw: '{{ avalaible_ngws.result[0] }}' + + #- name: Get all NAT gateways with specific filters (state and subnet) - CHECK_MODE + # ec2_vpc_nat_gateway_info: + # filters: + # state: ['available'] + # subnet-id: "{{ subnet_id }}" + # register: avalaible_ngws + + #- name: Assert success - CHECK_MODE + # assert: + # that: + # - avalaible_ngws is successful + # - avalaible_ngws.result | length == 1 + # - '"create_time" in first_ngw' + # - '"nat_gateway_addresses" in first_ngw' + # - '"nat_gateway_id" in first_ngw' + # - first_ngw.nat_gateway_id == nat_gateway_id + # - '"state" in first_ngw' + # - first_ngw.state == 'available' + # - '"subnet_id" in first_ngw' + # - first_ngw.subnet_id == subnet_id + # - '"tags" in first_ngw' + # - '"vpc_id" in first_ngw' + # - first_ngw.vpc_id == vpc_id + # vars: + # first_ngw: '{{ avalaible_ngws.result[0] }}' + # ============================================================ - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id @@ -154,7 +256,19 @@ assert: that: - not create_ngw.changed - + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + # - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id - CHECK_MODE # ec2_vpc_nat_gateway: # subnet_id: "{{ subnet_id }}" @@ -166,7 +280,19 @@ # - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE # assert: # that: - # - not create_ngw.changed + # - not create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # ============================================================ @@ -181,6 +307,18 @@ # assert: # that: # - create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # - name: Create new nat gateway with eip address - CHECK_MODE # ec2_vpc_nat_gateway: @@ -194,6 +332,18 @@ # assert: # that: # - create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # ============================================================ @@ -208,6 +358,18 @@ # assert: # that: # - not create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # - name: Trying this again for idempotency - create new nat gateway with eip address - CHECK_MODE # ec2_vpc_nat_gateway: @@ -221,6 +383,18 @@ # assert: # that: # - not create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # ============================================================ @@ -237,6 +411,18 @@ assert: that: - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id # - name: Create new nat gateway only if one does not exist already - CHECK_MODE # ec2_vpc_nat_gateway: @@ -250,7 +436,71 @@ # assert: # that: # - not create_ngw.changed + # - '"create_time" in create_ngw' + # - '"nat_gateway_addresses" in create_ngw' + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id + + - name: Fetch NAT gateway by ID (list) + ec2_vpc_nat_gateway_info: + nat_gateway_ids: + - "{{ nat_gateway_id }}" + register: ngw_info + retries: 10 + until: ngw_info is not failed + - name: Check NAT gateway exists + assert: + that: + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in first_ngw' + - '"nat_gateway_addresses" in first_ngw' + - '"nat_gateway_id" in first_ngw' + - first_ngw.nat_gateway_id == nat_gateway_id + - '"state" in first_ngw' + - first_ngw.state == 'available' + - '"subnet_id" in first_ngw' + - first_ngw.subnet_id == subnet_id + - '"tags" in first_ngw' + - '"vpc_id" in first_ngw' + - first_ngw.vpc_id == vpc_id + vars: + first_ngw: '{{ ngw_info.result[0] }}' + + # - name: Fetch NAT gateway by ID (list) - CHECK_MODE + # ec2_vpc_nat_gateway_info: + # nat_gateway_ids: + # - "{{ nat_gateway_id }}" + # register: ngw_info + # check_mode: yes + + # - name: Check NAT gateway exists - CHECK_MODE + # assert: + # that: + # - '"internet_gateways" in igw_info' + # - avalaible_ngws.result | length == 1 + # - '"create_time" in first_ngw' + # - '"nat_gateway_addresses" in first_ngw' + # - '"nat_gateway_id" in first_ngw' + # - first_ngw.nat_gateway_id == nat_gateway_id + # - '"state" in first_ngw' + # - first_ngw.state == 'available' + # - '"subnet_id" in first_ngw' + # - first_ngw.subnet_id == subnet_id + # - '"tags" in first_ngw' + # - '"vpc_id" in first_ngw' + # - first_ngw.vpc_id == vpc_id + # vars: + # first_ngw: '{{ ngw_info.result[0] }}' # ============================================================ - name: Delete NAT gateway @@ -266,6 +516,17 @@ assert: that: - delete_nat_gateway.changed + - '"delete_time" in delete_nat_gateway' + - '"nat_gateway_addresses" in delete_nat_gateway' + - '"nat_gateway_id" in delete_nat_gateway' + - delete_nat_gateway.nat_gateway_id == nat_gateway_id + - '"state" in delete_nat_gateway' + - delete_nat_gateway.state == 'deleted' + - '"subnet_id" in delete_nat_gateway' + - delete_nat_gateway.subnet_id == subnet_id + - '"tags" in delete_nat_gateway' + - '"vpc_id" in delete_nat_gateway' + - delete_nat_gateway.vpc_id == vpc_id # - name: Delete NAT gateway - CHECK_MODE # ec2_vpc_nat_gateway: @@ -278,7 +539,19 @@ # - name: Assert state=absent (expected changed=true) - CHECK_MODE # assert: # that: - # - delete_nat_gateway.changed + # - delete_nat_gateway.changed + # - '"delete_time" in delete_nat_gateway' + # - '"nat_gateway_addresses" in delete_nat_gateway' + # - '"nat_gateway_id" in delete_nat_gateway' + # - delete_nat_gateway.nat_gateway_id == nat_gateway_id + # - '"state" in delete_nat_gateway' + # - delete_nat_gateway.state == 'deleted' + # - '"subnet_id" in delete_nat_gateway' + # - delete_nat_gateway.subnet_id == subnet_id + # - '"tags" in delete_nat_gateway' + # - '"vpc_id" in delete_nat_gateway' + # - delete_nat_gateway.vpc_id == vpc_id + # ============================================================ - name: Create new NAT gateway with eip allocation-id and tags @@ -295,6 +568,25 @@ assert: that: - create_ngw.changed + - '"create_time" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - create_ngw.tags | length == 2 + - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + + - name: "set facts: NAT gateway ID" + set_fact: + ngw_id: "{{ create_ngw.nat_gateway_id }}" # - name: Create new NAT gateway with eip allocation-id and tags - CHECK_MODE # ec2_vpc_nat_gateway: @@ -310,7 +602,21 @@ # - name: Assert creation happened (expected changed=true) - CHECK_MODE # assert: # that: - # - create_ngw.changed + # - create_ngw.changed + # - '"create_time" in create_ngw' + # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + # - '"nat_gateway_id" in create_ngw' + # - create_ngw.nat_gateway_id.startswith("nat-") + # - '"state" in create_ngw' + # - create_ngw.state == 'available' + # - '"subnet_id" in create_ngw' + # - create_ngw.subnet_id == subnet_id + # - '"tags" in create_ngw' + # - create_ngw.tags | length == 2 + # - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + # - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + # - '"vpc_id" in create_ngw' + # - create_ngw.vpc_id == vpc_id # ============================================================ @@ -328,6 +634,18 @@ assert: that: - not update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + + # - name: Update the tags (no change) - CHECK_MODE # ec2_vpc_nat_gateway: @@ -344,6 +662,82 @@ # assert: # that: # - not update_tags_ngw.changed + # - '"nat_gateway_id" in update_tags_ngw' + # - update_tags_ngw.nat_gateway_id == ngw_id + # - '"subnet_id" in update_tags_ngw' + # - update_tags_ngw.subnet_id == subnet_id + # - '"tags" in update_tags_ngw' + # - update_tags_ngw.tags | length == 2 + # - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + # - '"vpc_id" in update_tags_ngw' + # - update_tags_ngw.vpc_id == vpc_id + + + # ============================================================ + - name: Gather information about a filtered list of NAT Gateways using tags and state + ec2_vpc_nat_gateway_info: + filters: + "tag:Tag Two": 'two {{ resource_prefix }}' + state: ['available'] + register: ngw_info + + - name: Assert success + assert: + that: + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in second_ngw' + - '"nat_gateway_addresses" in second_ngw' + - '"nat_gateway_id" in second_ngw' + - second_ngw.nat_gateway_id == ngw_id + - '"state" in second_ngw' + - second_ngw.state == 'available' + - '"subnet_id" in second_ngw' + - second_ngw.subnet_id == subnet_id + - '"tags" in second_ngw' + - second_ngw.tags | length == 2 + - '"tag_one" in second_ngw.tags' + - '"Tag Two" in second_ngw.tags' + - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in second_ngw' + - second_ngw.vpc_id == vpc_id + vars: + second_ngw: '{{ ngw_info.result[0] }}' + + + #- name: Gather information about a filtered list of NAT Gateways using tags and state - CHECK_MODE + # ec2_vpc_nat_gateway_info: + # filters: + # "tag:Tag Two": 'two {{ resource_prefix }}' + # state: ['available'] + # register: ngw_info + # check_mode: yes + + #- name: Assert success - CHECK_MODE + # assert: + # that: + # - ngw_info is successful + # - ngw_info.result | length == 1 + # - '"create_time" in second_ngw' + # - '"nat_gateway_addresses" in second_ngw' + # - '"nat_gateway_id" in second_ngw' + # - second_ngw.nat_gateway_id == ngw_id + # - '"state" in second_ngw' + # - second_ngw.state == 'available' + # - '"subnet_id" in second_ngw' + # - second_ngw.subnet_id == subnet_id + # - '"tags" in second_ngw' + # - second_ngw.tags | length == 2 + # - '"tag_one" in second_ngw.tags' + # - '"Tag Two" in second_ngw.tags' + # - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + # - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + # - '"vpc_id" in second_ngw' + # - second_ngw.vpc_id == vpc_id + # vars: + # second_ngw: '{{ ngw_info.result[0] }}' # ============================================================ @@ -360,7 +754,18 @@ - name: Assert tag update would happen (expected changed=true) assert: that: - - update_tags_ngw.changed + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + # - name: Update the tags - remove and add - CHECK_MODE # ec2_vpc_nat_gateway: @@ -376,7 +781,44 @@ # - name: Assert tag update would happen (expected changed=true) - CHECK_MODE # assert: # that: - # - update_tags_ngw.changed + # - update_tags_ngw.changed + # - '"nat_gateway_id" in update_tags_ngw' + # - update_tags_ngw.nat_gateway_id == ngw_id + # - '"subnet_id" in update_tags_ngw' + # - update_tags_ngw.subnet_id == subnet_id + # - '"tags" in update_tags_ngw' + # - update_tags_ngw.tags | length == 2 + # - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + # - '"vpc_id" in update_tags_ngw' + # - update_tags_ngw.vpc_id == vpc_id + + + # ============================================================ + - name: Gather information about a filtered list of NAT Gateways using tags (no match) + ec2_vpc_nat_gateway_info: + filters: + "tag:tag_one": '{{ resource_prefix }} One' + register: ngw_info + + - name: Assert success + assert: + that: + - ngw_info is successful + - ngw_info.result | length == 0 + + #- name: Gather information about a filtered list of NAT Gateways using tags (no match) - CHECK_MODE + # ec2_vpc_nat_gateway_info: + # filters: + # "tag:tag_one": '{{ resource_prefix }} One' + # register: ngw_info + # check_mode: yes + + #- name: Assert success - CHECK_MODE + # assert: + # that: + # - ngw_info is successful + # - ngw_info.result | length == 0 # ============================================================ @@ -395,6 +837,18 @@ assert: that: - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 3 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + # - name: Update the tags add without purge - CHECK_MODE # ec2_vpc_nat_gateway: @@ -411,7 +865,19 @@ # - name: Assert tags would be added - CHECK_MODE # assert: # that: - # - update_tags_ngw.changed + # - update_tags_ngw.changed + # - '"nat_gateway_id" in update_tags_ngw' + # - update_tags_ngw.nat_gateway_id == ngw_id + # - '"subnet_id" in update_tags_ngw' + # - update_tags_ngw.subnet_id == subnet_id + # - '"tags" in update_tags_ngw' + # - update_tags_ngw.tags | length == 3 + # - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + # - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + # - '"vpc_id" in update_tags_ngw' + # - update_tags_ngw.vpc_id == vpc_id + # ============================================================ @@ -426,6 +892,14 @@ assert: that: - delete_tags_ngw.changed + - '"nat_gateway_id" in delete_tags_ngw' + - delete_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in delete_tags_ngw' + - delete_tags_ngw.subnet_id == subnet_id + - '"tags" in delete_tags_ngw' + - delete_tags_ngw.tags | length == 0 + - '"vpc_id" in delete_tags_ngw' + - delete_tags_ngw.vpc_id == vpc_id # - name: Remove all tags - CHECK_MODE # ec2_vpc_nat_gateway: @@ -438,7 +912,15 @@ # - name: assert tags would be removed - CHECK_MODE # assert: # that: - # - delete_tags_ngw.changed + # - delete_tags_ngw.changed + # - '"nat_gateway_id" in delete_tags_ngw' + # - delete_tags_ngw.nat_gateway_id == ngw_id + # - '"subnet_id" in delete_tags_ngw' + # - delete_tags_ngw.subnet_id == subnet_id + # - '"tags" in delete_tags_ngw' + # - delete_tags_ngw.tags | length == 0 + # - '"vpc_id" in delete_tags_ngw' + # - delete_tags_ngw.vpc_id == vpc_id @@ -461,10 +943,18 @@ assert: that: - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 4 - 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 ❤️' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # - name: Update with CamelCase tags - CHECK_MODE @@ -480,15 +970,24 @@ # snake_case: 'simple_snake_case ❤️' # wait: yes # register: update_tags_ngw + # check_mode: yes #- name: Assert tags would be added - CHECK_MODE # assert: # that: # - update_tags_ngw.changed + # - '"nat_gateway_id" in update_tags_ngw' + # - update_tags_ngw.nat_gateway_id == ngw_id + # - '"subnet_id" in update_tags_ngw' + # - update_tags_ngw.subnet_id == subnet_id + # - '"tags" in update_tags_ngw' + # - update_tags_ngw.tags | length == 4 # - 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 ❤️' + # - '"vpc_id" in update_tags_ngw' + # - update_tags_ngw.vpc_id == vpc_id # ============================================================ From 1d374bc0c2b38e3fc334bc5d248be520d9566d57 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 25 Feb 2021 01:21:24 +0100 Subject: [PATCH 18/31] move describe_addresses call back to non-paginated (pagination not supported) (#441) This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/2fe5c31f4d5d761d13f1ba146855901231c2525a --- plugins/modules/ec2_vpc_nat_gateway.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 0fdd6c96b6d..428f82b392b 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -278,12 +278,6 @@ DRY_RUN_MSGS = 'DryRun Mode:' -@AWSRetry.jittered_backoff(retries=10) -def _describe_addresses(client, **params): - paginator = client.get_paginator('describe_addresses') - return paginator.paginate(**params).build_full_result()['Addresses'] - - @AWSRetry.jittered_backoff(retries=10) def _describe_nat_gateways(client, **params): paginator = client.get_paginator('describe_nat_gateways') @@ -546,7 +540,7 @@ def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): err_msg = "" try: if not check_mode: - allocations = _describe_addresses(client, **params) + allocations = client.describe_addresses(aws_retry=True, **params) if len(allocations) == 1: allocation = allocations[0] else: @@ -644,7 +638,7 @@ def release_address(client, allocation_id, check_mode=False): ip_released = False try: - _describe_addresses(client, aws_retry=True, AllocationIds=[allocation_id]) + client.describe_addresses(aws_retry=True, AllocationIds=[allocation_id]) except botocore.exceptions.ClientError as e: # IP address likely already released # Happens with gateway in 'deleted' state that From 1e61cf62a7aef14bba98113ba9efc843997cf1e3 Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Thu, 25 Feb 2021 21:11:13 +0100 Subject: [PATCH 19/31] ec2_vpc_nat_gateway_info: add retry decorator (#446) * Solve RequestLimitExceeded error by adding the retry decorator Signed-off-by: Alina Buzachis Co-authored-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/52fb23054101acbd78e13a45048ddcf935899586 --- plugins/modules/ec2_vpc_nat_gateway_info.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 97816c72362..7d31eeac993 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -84,6 +84,7 @@ 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.ec2 import camel_dict_to_snake_dict from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list @@ -102,7 +103,7 @@ def get_nat_gateways(client, module, nat_gateway_id=None): params['NatGatewayIds'] = module.params.get('nat_gateway_ids') try: - result = json.loads(json.dumps(client.describe_nat_gateways(**params), default=date_handler)) + result = json.loads(json.dumps(client.describe_nat_gateways(aws_retry=True, **params), default=date_handler)) except Exception as e: module.fail_json(msg=to_native(e)) @@ -131,7 +132,7 @@ def main(): date='2021-12-01', collection_name='community.aws') try: - connection = module.client('ec2') + connection = 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') From 1c5950fb294e4256453fbb7a3fb132818b528250 Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Wed, 10 Mar 2021 11:47:13 +0100 Subject: [PATCH 20/31] Fix broken check_mode (#436) * ec2_vpc_nat_gateway: fix broken check_mode * fix broken check_mode (remove hard coded values) Signed-off-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/044b30c7459b9bc2937c444a2f2641ba5adfdc91 --- plugins/modules/ec2_vpc_nat_gateway.py | 127 +-- .../ec2_vpc_nat_gateway/tasks/main.yml | 968 ++++++++---------- 2 files changed, 481 insertions(+), 614 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 428f82b392b..11c271434d9 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -247,36 +247,6 @@ from ansible.module_utils.six import string_types from ansible.module_utils._text import to_native -DRY_RUN_GATEWAYS = [ - { - "nat_gateway_id": "nat-123456789", - "subnet_id": "subnet-123456789", - "nat_gateway_addresses": [ - { - "public_ip": "55.55.55.55", - "network_interface_id": "eni-1234567", - "private_ip": "10.0.0.102", - "allocation_id": "eipalloc-1234567" - } - ], - "state": "available", - "create_time": "2016-03-05T05:19:20.282000+00:00", - "vpc_id": "vpc-12345678" - } -] - -DRY_RUN_ALLOCATION_UNCONVERTED = { - 'Addresses': [ - { - 'PublicIp': '55.55.55.55', - 'Domain': 'vpc', - 'AllocationId': 'eipalloc-1234567' - } - ] -} - -DRY_RUN_MSGS = 'DryRun Mode:' - @AWSRetry.jittered_backoff(retries=10) def _describe_nat_gateways(client, **params): @@ -344,22 +314,11 @@ def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, ] try: - if not check_mode: - gateways = _describe_nat_gateways(client, **params) - if gateways: - for gw in gateways: - existing_gateways.append(camel_dict_to_snake_dict(gw)) - gateways_retrieved = True - else: - gateways_retrieved = True - if nat_gateway_id: - if DRY_RUN_GATEWAYS[0]['nat_gateway_id'] == nat_gateway_id: - existing_gateways = DRY_RUN_GATEWAYS - elif subnet_id: - if DRY_RUN_GATEWAYS[0]['subnet_id'] == subnet_id: - existing_gateways = DRY_RUN_GATEWAYS - err_msg = '{0} Retrieving gateways'.format(DRY_RUN_MSGS) - + gateways = _describe_nat_gateways(client, **params) + if gateways: + for gw in gateways: + existing_gateways.append(camel_dict_to_snake_dict(gw)) + gateways_retrieved = True except botocore.exceptions.ClientError as e: err_msg = str(e) @@ -422,8 +381,6 @@ def wait_for_status(client, wait_timeout, nat_gateway_id, status, ) if gws_retrieved and nat_gateways: nat_gateway = nat_gateways[0] - if check_mode: - nat_gateway['state'] = status if nat_gateway.get('state') == status: status_achieved = True @@ -500,6 +457,7 @@ def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, client, subnet_id, states=states, check_mode=check_mode ) ) + if not gws_retrieved: return gateways, allocation_id_exists for gw in gws: @@ -538,21 +496,14 @@ def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): } allocation_id = None err_msg = "" + try: - if not check_mode: - allocations = client.describe_addresses(aws_retry=True, **params) - if len(allocations) == 1: - allocation = allocations[0] - else: - allocation = None + allocations = client.describe_addresses(aws_retry=True, **params)['Addresses'] + if len(allocations) == 1: + allocation = allocations[0] else: - dry_run_eip = ( - DRY_RUN_ALLOCATION_UNCONVERTED['Addresses'][0]['PublicIp'] - ) - if dry_run_eip == eip_address: - allocation = DRY_RUN_ALLOCATION_UNCONVERTED['Addresses'][0] - else: - allocation = None + allocation = None + if allocation: if allocation.get('Domain') != 'vpc': err_msg = ( @@ -595,16 +546,15 @@ def allocate_eip_address(client, check_mode=False): params = { 'Domain': 'vpc', } + + if check_mode: + ip_allocated = True + new_eip = None + return ip_allocated, err_msg, new_eip + try: - if check_mode: - ip_allocated = True - random_numbers = ( - ''.join(str(x) for x in random.sample(range(0, 9), 7)) - ) - new_eip = 'eipalloc-{0}'.format(random_numbers) - else: - new_eip = client.allocate_address(aws_retry=True, **params)['AllocationId'] - ip_allocated = True + new_eip = client.allocate_address(aws_retry=True, **params)['AllocationId'] + ip_allocated = True err_msg = 'eipalloc id {0} created'.format(new_eip) except botocore.exceptions.ClientError as e: @@ -633,6 +583,7 @@ def release_address(client, allocation_id, check_mode=False): Boolean, string """ err_msg = '' + if check_mode: return True, '' @@ -711,22 +662,24 @@ def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_to success = False token_provided = False err_msg = "" + result = {} if client_token: token_provided = True params['ClientToken'] = client_token + if check_mode: + success = True + changed = True + return success, changed, err_msg, result + try: - if not check_mode: - result = camel_dict_to_snake_dict(client.create_nat_gateway(aws_retry=True, **params)["NatGateway"]) - else: - result = DRY_RUN_GATEWAYS[0] - result['create_time'] = datetime.datetime.utcnow() - result['nat_gateway_addresses'][0]['allocation_id'] = allocation_id - result['subnet_id'] = subnet_id + result = camel_dict_to_snake_dict(client.create_nat_gateway(aws_retry=True, **params)["NatGateway"]) success = True changed = True + create_time = result['create_time'].replace(tzinfo=None) + if token_provided and (request_time > create_time): changed = False elif wait: @@ -815,10 +768,11 @@ def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, success = False changed = False err_msg = "" - results = list() + results = {} if not allocation_id and not eip_address: 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) @@ -855,6 +809,7 @@ def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=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 @@ -933,8 +888,14 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, success = False changed = False err_msg = "" - results = list() + results = {} states = ['pending', 'available'] + + if check_mode: + changed = True + success = True + return success, changed, err_msg, results + try: exist, err_msg, gw = ( get_nat_gateways( @@ -944,8 +905,7 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, ) if exist and len(gw) == 1: results = gw[0] - if not check_mode: - client.delete_nat_gateway(aws_retry=True, **params) + client.delete_nat_gateway(aws_retry=True, **params) allocation_id = ( results['nat_gateway_addresses'][0]['allocation_id'] @@ -990,6 +950,10 @@ def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): final_tags = [] changed = False + if check_mode and nat_gw_id is None: + # We can't describe tags without an EIP id, we might get here when creating a new EIP in check_mode + return final_tags, changed + filters = ansible_dict_to_boto3_filter_list({'resource-id': nat_gw_id, 'resource-type': 'natgateway'}) cur_tags = None try: @@ -1041,6 +1005,7 @@ def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): 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 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 f43a3ece55c..3dcb70a153e 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -1,16 +1,4 @@ --- -# ============================================================ -# 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: @@ -22,7 +10,7 @@ - amazon.aws block: - + # ============================================================ - name: Create a VPC ec2_vpc_net: @@ -35,11 +23,20 @@ assert: that: - vpc_result is successful + - '"vpc" in vpc_result' + - '"cidr_block" in vpc_result.vpc' + - vpc_result.vpc.cidr_block == vpc_cidr + - '"id" in vpc_result.vpc' + - vpc_result.vpc.id.startswith("vpc-") + - '"state" in vpc_result.vpc' + - vpc_result.vpc.state == 'available' + - '"tags" in vpc_result.vpc' - name: "set fact: VPC ID" set_fact: vpc_id: "{{ vpc_result.vpc.id }}" + # ============================================================ - name: Allocate a new EIP ec2_eip: @@ -52,7 +49,9 @@ assert: that: - eip_result is successful + - '"allocation_id" in eip_result' - 'eip_result.allocation_id.startswith("eipalloc-")' + - '"public_ip" in eip_result' - name: "set fact: EIP allocation ID and EIP public IP" set_fact: @@ -72,9 +71,14 @@ assert: that: - subnet_result is successful - - subnet_result.subnet.id.startswith("subnet-") + - '"subnet" in subnet_result' + - '"cidr_block" in subnet_result.subnet' - subnet_result.subnet.cidr_block == subnet_cidr + - '"id" in subnet_result.subnet' + - subnet_result.subnet.id.startswith("subnet-") + - '"state" in subnet_result.subnet' - subnet_result.subnet.state == 'available' + - '"tags" in subnet_result.subnet' - subnet_result.subnet.vpc_id == vpc_id - name: "set fact: VPC subnet ID" @@ -83,34 +87,32 @@ # ============================================================ - - name: Search for NAT gateways by subnet - no matches + - name: Search for NAT gateways by subnet (no matches) - CHECK_MODE ec2_vpc_nat_gateway_info: filters: subnet-id: "{{ subnet_id }}" state: ['available'] register: existing_ngws - retries: 10 - until: existing_ngws is not failed + check_mode: yes - - name: Assert no NAT gateway found + - name: Assert no NAT gateway found - CHECK_MODE assert: that: - existing_ngws is successful - (existing_ngws.result|length) == 0 - # - name: Search for NAT gateways by subnet (no matches) - CHECK_MODE - # ec2_vpc_nat_gateway_info: - # filters: - # subnet-id: "{{ subnet_id }}" - # state: ['available'] - # register: existing_ngws - # check_mode: yes + - name: Search for NAT gateways by subnet - no matches + ec2_vpc_nat_gateway_info: + filters: + subnet-id: "{{ subnet_id }}" + state: ['available'] + register: existing_ngws - # - name: Assert no NAT gateway found - CHECK_MODE - # assert: - # that: - # - existing_ngws is successful - # - (existing_ngws.result|length) == 0 + - name: Assert no NAT gateway found + assert: + that: + - existing_ngws is successful + - (existing_ngws.result|length) == 0 # ============================================================ @@ -129,14 +131,25 @@ # ============================================================ + - 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: 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: @@ -160,99 +173,44 @@ 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - - - # ============================================================ + + # ============================================================ - name: Get NAT gateway with specific filters (state and subnet) ec2_vpc_nat_gateway_info: - filters: - subnet-id: "{{ subnet_id }}" - state: ['available'] + filters: + subnet-id: "{{ subnet_id }}" + state: ['available'] register: avalaible_ngws - retries: 10 - until: avalaible_ngws is not failed - name: Assert success assert: that: - - avalaible_ngws is successful - - avalaible_ngws.result | length == 1 - - '"create_time" in first_ngw' - - '"nat_gateway_addresses" in first_ngw' - - '"nat_gateway_id" in first_ngw' - - first_ngw.nat_gateway_id == nat_gateway_id - - '"state" in first_ngw' - - first_ngw.state == 'available' - - '"subnet_id" in first_ngw' - - first_ngw.subnet_id == subnet_id - - '"tags" in first_ngw' - - '"vpc_id" in first_ngw' - - first_ngw.vpc_id == vpc_id + - avalaible_ngws is successful + - avalaible_ngws.result | length == 1 + - '"create_time" in first_ngw' + - '"nat_gateway_addresses" in first_ngw' + - '"nat_gateway_id" in first_ngw' + - first_ngw.nat_gateway_id == nat_gateway_id + - '"state" in first_ngw' + - first_ngw.state == 'available' + - '"subnet_id" in first_ngw' + - first_ngw.subnet_id == subnet_id + - '"tags" in first_ngw' + - '"vpc_id" in first_ngw' + - first_ngw.vpc_id == vpc_id vars: first_ngw: '{{ avalaible_ngws.result[0] }}' - - #- name: Get all NAT gateways with specific filters (state and subnet) - CHECK_MODE - # ec2_vpc_nat_gateway_info: - # filters: - # state: ['available'] - # subnet-id: "{{ subnet_id }}" - # register: avalaible_ngws - - #- name: Assert success - CHECK_MODE - # assert: - # that: - # - avalaible_ngws is successful - # - avalaible_ngws.result | length == 1 - # - '"create_time" in first_ngw' - # - '"nat_gateway_addresses" in first_ngw' - # - '"nat_gateway_id" in first_ngw' - # - first_ngw.nat_gateway_id == nat_gateway_id - # - '"state" in first_ngw' - # - first_ngw.state == 'available' - # - '"subnet_id" in first_ngw' - # - first_ngw.subnet_id == subnet_id - # - '"tags" in first_ngw' - # - '"vpc_id" in first_ngw' - # - first_ngw.vpc_id == vpc_id - # vars: - # first_ngw: '{{ avalaible_ngws.result[0] }}' - # ============================================================ - - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id + - 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 - retries: 10 - until: create_ngw is not failed + check_mode: yes - - name: Assert recreation would do nothing (expected changed=false) + - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE assert: that: - not create_ngw.changed @@ -269,143 +227,64 @@ - '"vpc_id" in create_ngw' - create_ngw.vpc_id == vpc_id - # - 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - - - # ============================================================ - #- 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - - # - 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - - - # ============================================================ - # - 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - - # - 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id + - 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 + - name: Assert recreation would do nothing (expected changed=false) + assert: + that: + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + # ============================================================ + - 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 + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + - 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: @@ -423,39 +302,124 @@ - '"tags" in create_ngw' - '"vpc_id" in create_ngw' - create_ngw.vpc_id == 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 + - '"allocation_id" in eip_result' + - 'eip_result.allocation_id.startswith("eipalloc-")' + - '"public_ip" in eip_result' + + - name: "set fact: EIP allocation ID and EIP public IP" + set_fact: + second_eip_address: "{{ eip_result.public_ip }}" + second_allocation_id: "{{ eip_result.allocation_id }}" - # - 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 - # - '"create_time" in create_ngw' - # - '"nat_gateway_addresses" in create_ngw' - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id + - name: Create new nat gateway with eip address - CHECK_MODE + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + eip_address: "{{ second_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: Create new NAT gateway with eip address + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + eip_address: "{{ second_eip_address }}" + wait: yes + register: create_ngw + - name: Assert creation happened (expected changed=true) + assert: + that: + - create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + + # ============================================================ + - 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: "{{ second_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 + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + - name: Trying this again for idempotency - create new NAT gateway with eip address + ec2_vpc_nat_gateway: + subnet_id: "{{ subnet_id }}" + eip_address: "{{ second_eip_address }}" + wait: yes + register: create_ngw + + - name: Assert recreation would do nothing (expected changed=false) + assert: + that: + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + + # ============================================================ - name: Fetch NAT gateway by ID (list) ec2_vpc_nat_gateway_info: nat_gateway_ids: - "{{ nat_gateway_id }}" register: ngw_info - retries: 10 - until: ngw_info is not failed - name: Check NAT gateway exists assert: @@ -476,41 +440,27 @@ vars: first_ngw: '{{ ngw_info.result[0] }}' - # - name: Fetch NAT gateway by ID (list) - CHECK_MODE - # ec2_vpc_nat_gateway_info: - # nat_gateway_ids: - # - "{{ nat_gateway_id }}" - # register: ngw_info - # check_mode: yes - - # - name: Check NAT gateway exists - CHECK_MODE - # assert: - # that: - # - '"internet_gateways" in igw_info' - # - avalaible_ngws.result | length == 1 - # - '"create_time" in first_ngw' - # - '"nat_gateway_addresses" in first_ngw' - # - '"nat_gateway_id" in first_ngw' - # - first_ngw.nat_gateway_id == nat_gateway_id - # - '"state" in first_ngw' - # - first_ngw.state == 'available' - # - '"subnet_id" in first_ngw' - # - first_ngw.subnet_id == subnet_id - # - '"tags" in first_ngw' - # - '"vpc_id" in first_ngw' - # - first_ngw.vpc_id == vpc_id - # vars: - # first_ngw: '{{ ngw_info.result[0] }}' # ============================================================ + - 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: 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: @@ -528,32 +478,24 @@ - '"vpc_id" in delete_nat_gateway' - delete_nat_gateway.vpc_id == vpc_id - # - 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 - # - '"delete_time" in delete_nat_gateway' - # - '"nat_gateway_addresses" in delete_nat_gateway' - # - '"nat_gateway_id" in delete_nat_gateway' - # - delete_nat_gateway.nat_gateway_id == nat_gateway_id - # - '"state" in delete_nat_gateway' - # - delete_nat_gateway.state == 'deleted' - # - '"subnet_id" in delete_nat_gateway' - # - delete_nat_gateway.subnet_id == subnet_id - # - '"tags" in delete_nat_gateway' - # - '"vpc_id" in delete_nat_gateway' - # - delete_nat_gateway.vpc_id == vpc_id - # ============================================================ + - 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: Create new NAT gateway with eip allocation-id and tags ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" @@ -583,44 +525,13 @@ - '"vpc_id" in create_ngw' - create_ngw.vpc_id == vpc_id - - name: "set facts: NAT gateway ID" set_fact: ngw_id: "{{ create_ngw.nat_gateway_id }}" - # - 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 - # - '"create_time" in create_ngw' - # - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - # - '"nat_gateway_id" in create_ngw' - # - create_ngw.nat_gateway_id.startswith("nat-") - # - '"state" in create_ngw' - # - create_ngw.state == 'available' - # - '"subnet_id" in create_ngw' - # - create_ngw.subnet_id == subnet_id - # - '"tags" in create_ngw' - # - create_ngw.tags | length == 2 - # - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - # - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - # - '"vpc_id" in create_ngw' - # - create_ngw.vpc_id == vpc_id - # ============================================================ - - name: Update the tags (no change) + - name: Update the tags (no change) - CHECK_MODE ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" allocation_id: "{{ allocation_id }}" @@ -629,8 +540,9 @@ "Tag Two": 'two {{ resource_prefix }}' wait: yes register: update_tags_ngw + check_mode: yes - - name: assert tag update would do nothing (expected changed=false) + - name: assert tag update would do nothing (expected changed=false) - CHECK_MODE assert: that: - not update_tags_ngw.changed @@ -645,44 +557,42 @@ - '"vpc_id" in update_tags_ngw' - update_tags_ngw.vpc_id == vpc_id + - 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: 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 - # - '"nat_gateway_id" in update_tags_ngw' - # - update_tags_ngw.nat_gateway_id == ngw_id - # - '"subnet_id" in update_tags_ngw' - # - update_tags_ngw.subnet_id == subnet_id - # - '"tags" in update_tags_ngw' - # - update_tags_ngw.tags | length == 2 - # - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - # - '"vpc_id" in update_tags_ngw' - # - update_tags_ngw.vpc_id == vpc_id + - name: assert tag update would do nothing (expected changed=false) + assert: + that: + - not update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # ============================================================ - - name: Gather information about a filtered list of NAT Gateways using tags and state + - name: Gather information about a filtered list of NAT Gateways using tags and state - CHECK_MODE ec2_vpc_nat_gateway_info: filters: "tag:Tag Two": 'two {{ resource_prefix }}' state: ['available'] register: ngw_info + check_mode: yes - - name: Assert success + - name: Assert success - CHECK_MODE assert: that: - ngw_info is successful @@ -705,43 +615,41 @@ - second_ngw.vpc_id == vpc_id vars: second_ngw: '{{ ngw_info.result[0] }}' - - #- name: Gather information about a filtered list of NAT Gateways using tags and state - CHECK_MODE - # ec2_vpc_nat_gateway_info: - # filters: - # "tag:Tag Two": 'two {{ resource_prefix }}' - # state: ['available'] - # register: ngw_info - # check_mode: yes - - #- name: Assert success - CHECK_MODE - # assert: - # that: - # - ngw_info is successful - # - ngw_info.result | length == 1 - # - '"create_time" in second_ngw' - # - '"nat_gateway_addresses" in second_ngw' - # - '"nat_gateway_id" in second_ngw' - # - second_ngw.nat_gateway_id == ngw_id - # - '"state" in second_ngw' - # - second_ngw.state == 'available' - # - '"subnet_id" in second_ngw' - # - second_ngw.subnet_id == subnet_id - # - '"tags" in second_ngw' - # - second_ngw.tags | length == 2 - # - '"tag_one" in second_ngw.tags' - # - '"Tag Two" in second_ngw.tags' - # - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - # - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - # - '"vpc_id" in second_ngw' - # - second_ngw.vpc_id == vpc_id - # vars: - # second_ngw: '{{ ngw_info.result[0] }}' + - name: Gather information about a filtered list of NAT Gateways using tags and state + ec2_vpc_nat_gateway_info: + filters: + "tag:Tag Two": 'two {{ resource_prefix }}' + state: ['available'] + register: ngw_info + + - name: Assert success + assert: + that: + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in second_ngw' + - '"nat_gateway_addresses" in second_ngw' + - '"nat_gateway_id" in second_ngw' + - second_ngw.nat_gateway_id == ngw_id + - '"state" in second_ngw' + - second_ngw.state == 'available' + - '"subnet_id" in second_ngw' + - second_ngw.subnet_id == subnet_id + - '"tags" in second_ngw' + - second_ngw.tags | length == 2 + - '"tag_one" in second_ngw.tags' + - '"Tag Two" in second_ngw.tags' + - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in second_ngw' + - second_ngw.vpc_id == vpc_id + vars: + second_ngw: '{{ ngw_info.result[0] }}' # ============================================================ - - name: Update the tags - remove and add + - name: Update the tags - remove and add - CHECK_MODE ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" allocation_id: "{{ allocation_id }}" @@ -750,8 +658,9 @@ "Tag Two": 'two {{ resource_prefix }}' wait: yes register: update_tags_ngw + check_mode: yes - - name: Assert tag update would happen (expected changed=true) + - name: Assert tag update would happen (expected changed=true) - CHECK_MODE assert: that: - update_tags_ngw.changed @@ -766,62 +675,90 @@ - '"vpc_id" in update_tags_ngw' - update_tags_ngw.vpc_id == vpc_id + - 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: 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 - # - '"nat_gateway_id" in update_tags_ngw' - # - update_tags_ngw.nat_gateway_id == ngw_id - # - '"subnet_id" in update_tags_ngw' - # - update_tags_ngw.subnet_id == subnet_id - # - '"tags" in update_tags_ngw' - # - update_tags_ngw.tags | length == 2 - # - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - # - '"vpc_id" in update_tags_ngw' - # - update_tags_ngw.vpc_id == vpc_id + - name: Assert tag update would happen (expected changed=true) + assert: + that: + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # ============================================================ - - name: Gather information about a filtered list of NAT Gateways using tags (no match) + - name: Gather information about a filtered list of NAT Gateways using tags and state (no match) - CHECK_MODE ec2_vpc_nat_gateway_info: filters: "tag:tag_one": '{{ resource_prefix }} One' + state: ['available'] register: ngw_info + check_mode: yes - - name: Assert success + - name: Assert success - CHECK_MODE assert: that: - ngw_info is successful - ngw_info.result | length == 0 - #- name: Gather information about a filtered list of NAT Gateways using tags (no match) - CHECK_MODE - # ec2_vpc_nat_gateway_info: - # filters: - # "tag:tag_one": '{{ resource_prefix }} One' - # register: ngw_info - # check_mode: yes + - name: Gather information about a filtered list of NAT Gateways using tags and state (no match) + ec2_vpc_nat_gateway_info: + filters: + "tag:tag_one": '{{ resource_prefix }} One' + state: ['available'] + register: ngw_info - #- name: Assert success - CHECK_MODE - # assert: - # that: - # - ngw_info is successful - # - ngw_info.result | length == 0 + - name: Assert success + assert: + that: + - ngw_info is successful + - ngw_info.result | length == 0 # ============================================================ + - 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 + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 3 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + - name: Update the tags add without purge ec2_vpc_nat_gateway: if_exist_do_not_create: yes @@ -850,37 +787,28 @@ - update_tags_ngw.vpc_id == vpc_id - # - 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 - # - '"nat_gateway_id" in update_tags_ngw' - # - update_tags_ngw.nat_gateway_id == ngw_id - # - '"subnet_id" in update_tags_ngw' - # - update_tags_ngw.subnet_id == subnet_id - # - '"tags" in update_tags_ngw' - # - update_tags_ngw.tags | length == 3 - # - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - # - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - # - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - # - '"vpc_id" in update_tags_ngw' - # - update_tags_ngw.vpc_id == vpc_id - + # ============================================================ + - 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 + - '"nat_gateway_id" in delete_tags_ngw' + - delete_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in delete_tags_ngw' + - delete_tags_ngw.subnet_id == subnet_id + - '"tags" in delete_tags_ngw' + - delete_tags_ngw.tags | length == 0 + - '"vpc_id" in delete_tags_ngw' + - delete_tags_ngw.vpc_id == vpc_id - # ============================================================ - name: Remove all tags ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" @@ -901,30 +829,40 @@ - '"vpc_id" in delete_tags_ngw' - delete_tags_ngw.vpc_id == vpc_id - # - 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 - # - '"nat_gateway_id" in delete_tags_ngw' - # - delete_tags_ngw.nat_gateway_id == ngw_id - # - '"subnet_id" in delete_tags_ngw' - # - delete_tags_ngw.subnet_id == subnet_id - # - '"tags" in delete_tags_ngw' - # - delete_tags_ngw.tags | length == 0 - # - '"vpc_id" in delete_tags_ngw' - # - delete_tags_ngw.vpc_id == vpc_id + # ============================================================ + - 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 + check_mode: yes + - name: Assert tags would be added - CHECK_MODE + assert: + that: + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 4 + - 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 ❤️' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id - # ============================================================ - name: Update with CamelCase tags ec2_vpc_nat_gateway: if_exist_do_not_create: yes @@ -957,56 +895,20 @@ - update_tags_ngw.vpc_id == vpc_id - # - 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 - # check_mode: yes - - #- name: Assert tags would be added - CHECK_MODE - # assert: - # that: - # - update_tags_ngw.changed - # - '"nat_gateway_id" in update_tags_ngw' - # - update_tags_ngw.nat_gateway_id == ngw_id - # - '"subnet_id" in update_tags_ngw' - # - update_tags_ngw.subnet_id == subnet_id - # - '"tags" in update_tags_ngw' - # - update_tags_ngw.tags | length == 4 - # - 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 ❤️' - # - '"vpc_id" in update_tags_ngw' - # - update_tags_ngw.vpc_id == vpc_id - # ============================================================ - - 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 + release_eip: yes state: absent wait: yes with_items: "{{ existing_ngws.result }}" From 7f3a9411b981a05d952c0dc4c3b00474fac75998 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 13 Mar 2021 20:10:09 +0100 Subject: [PATCH 21/31] More no_log=False to fix sanity tests (#474) * Add no_log=False to mark some more false-positives of the no_log check. * More false-positives confirmed by tremble. This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/67b6d751cc4ee5728577af2fe7b330f8cc7cd5c2 --- plugins/modules/ec2_vpc_nat_gateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 11c271434d9..b85d8ed97e8 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -1020,7 +1020,7 @@ def main(): wait_timeout=dict(type='int', default=320, required=False), release_eip=dict(type='bool', default=False), nat_gateway_id=dict(type='str'), - client_token=dict(type='str'), + client_token=dict(type='str', no_log=False), tags=dict(required=False, type='dict', aliases=['resource_tags']), purge_tags=dict(default=True, type='bool'), ) From e1499b6f5ff1ecaf02180ff07816ca15d0c2d960 Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Tue, 16 Mar 2021 23:28:33 +0100 Subject: [PATCH 22/31] ec2_vpc_nat_gateway cleanup (#445) * ec2_vpc_nat_gateway overall cleanup * use custm waiters to manage NAT gateway states (deleted and available) * imporve error handling * improve documentation examples * code cleaning Signed-off-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/9b60a2d5d50ff1d77e74cf79715ccebc4632757f --- plugins/modules/ec2_vpc_nat_gateway.py | 578 ++++++++---------- .../ec2_vpc_nat_gateway/tasks/main.yml | 6 +- 2 files changed, 250 insertions(+), 334 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index b85d8ed97e8..87511fa2582 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -6,7 +6,7 @@ __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: ec2_vpc_nat_gateway version_added: 1.0.0 @@ -50,7 +50,7 @@ type: bool tags: description: - - A dict of tags to apply to the internet gateway. + - A dict of tags to apply to the NAT gateway. - To remove all tags set I(tags={}) and I(purge_tags=true). aliases: [ 'resource_tags' ] type: dict @@ -88,13 +88,13 @@ - Allen Sanabria (@linuxdynasty) - Jon Hadfield (@jonhadfield) - Karen Cheng (@Etherdaemon) + - Alina Buzachis (@alinabuzachis) extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 - ''' -EXAMPLES = ''' +EXAMPLES = r''' # Note: These examples do not set authentication details, see the AWS Guide for details. - name: Create new nat gateway with client token. @@ -167,19 +167,30 @@ wait_timeout: 300 region: ap-southeast-2 -- name: Create new nat gateway using an allocation-id and tags. +- name: Create new nat gateway using 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 + Tag1: tag1 + Tag2: tag2 register: new_nat_gateway + +- name: Update tags without purge + community.aws.ec2_vpc_nat_gateway: + subnet_id: subnet-12345678 + allocation_id: eipalloc-12345678 + region: ap-southeast-2 + purge_tags: no + tags: + Tag3: tag3 + wait: yes + register: update_tags_nat_gateway ''' -RETURN = ''' +RETURN = r''' create_time: description: The ISO 8601 date time format in UTC. returned: In all cases. @@ -206,7 +217,7 @@ returned: When tags are present. sample: tags: - "Ansible": "Test" + "Ansible": "Test" vpc_id: description: id of the VPC. returned: In all cases. @@ -218,64 +229,79 @@ type: str sample: [ { - 'public_ip': '52.52.52.52', - 'network_interface_id': 'eni-12345', - 'private_ip': '10.0.0.100', - 'allocation_id': 'eipalloc-12345' + 'public_ip': '52.52.52.52', + 'network_interface_id': 'eni-12345', + 'private_ip': '10.0.0.100', + 'allocation_id': 'eipalloc-12345' } ] ''' import datetime -import random -import time try: import botocore except ImportError: pass # Handled by AnsibleAWSModule - 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.waiters import get_waiter 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 @AWSRetry.jittered_backoff(retries=10) def _describe_nat_gateways(client, **params): - paginator = client.get_paginator('describe_nat_gateways') - return paginator.paginate(**params).build_full_result()['NatGateways'] + try: + paginator = client.get_paginator('describe_nat_gateways') + return paginator.paginate(**params).build_full_result()['NatGateways'] + except is_boto3_error_code('InvalidNatGatewayID.NotFound'): + return None -def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, - states=None, check_mode=False): +def wait_for_status(client, module, waiter_name, nat_gateway_id): + wait_timeout = module.params.get('wait_timeout') + try: + waiter = get_waiter(client, waiter_name) + attempts = 1 + int(wait_timeout / waiter.config.delay) + waiter.wait( + NatGatewayIds=[nat_gateway_id], + WaiterConfig={'MaxAttempts': attempts} + ) + except botocore.exceptions.WaiterError as e: + module.fail_json_aws(e, msg="NAT gateway failed to reach expected state.") + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Unable to wait for NAT gateway state to update.") + + +def get_nat_gateways(client, module, subnet_id=None, nat_gateway_id=None, states=None): """Retrieve a list of NAT Gateways Args: client (botocore.client.EC2): Boto3 client + module: AnsibleAWSModule class instance Kwargs: subnet_id (str): The subnet_id the nat resides in. - nat_gateway_id (str): The Amazon nat id. + nat_gateway_id (str): The Amazon NAT id. states (list): States available (pending, failed, available, deleting, and deleted) default=None Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> subnet_id = 'subnet-12345678' - >>> get_nat_gateways(client, subnet_id) + >>> get_nat_gateways(client, module, subnet_id) [ true, "", { - "nat_gateway_id": "nat-123456789", - "subnet_id": "subnet-123456789", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", "nat_gateway_addresses": [ { "public_ip": "55.55.55.55", @@ -284,19 +310,20 @@ def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, "allocation_id": "eipalloc-1234567" } ], + "nat_gateway_id": "nat-123456789", "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", + "subnet_id": "subnet-123456789", + "tags": {}, "vpc_id": "vpc-12345678" } Returns: Tuple (bool, str, list) """ + params = dict() - err_msg = "" - gateways_retrieved = False existing_gateways = list() + if not states: states = ['available', 'pending'] if nat_gateway_id: @@ -318,100 +345,17 @@ def get_nat_gateways(client, subnet_id=None, nat_gateway_id=None, if gateways: for gw in gateways: existing_gateways.append(camel_dict_to_snake_dict(gw)) - gateways_retrieved = True - except botocore.exceptions.ClientError as e: - err_msg = str(e) - - return gateways_retrieved, err_msg, existing_gateways - - -def wait_for_status(client, wait_timeout, nat_gateway_id, status, - check_mode=False): - """Wait for the NAT Gateway to reach a status - Args: - client (botocore.client.EC2): Boto3 client - wait_timeout (int): Number of seconds to wait, until this timeout is reached. - nat_gateway_id (str): The Amazon nat id. - status (str): The status to wait for. - examples. status=available, status=deleted - - Basic Usage: - >>> client = boto3.client('ec2') - >>> subnet_id = 'subnet-12345678' - >>> allocation_id = 'eipalloc-12345678' - >>> wait_for_status(client, subnet_id, allocation_id) - [ - true, - "", - { - "nat_gateway_id": "nat-123456789", - "subnet_id": "subnet-1234567", - "nat_gateway_addresses": [ - { - "public_ip": "55.55.55.55", - "network_interface_id": "eni-1234567", - "private_ip": "10.0.0.102", - "allocation_id": "eipalloc-12345678" - } - ], - "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", - "vpc_id": "vpc-12345677" - } - ] - - Returns: - Tuple (bool, str, dict) - """ - polling_increment_secs = 5 - wait_timeout = time.time() + wait_timeout - status_achieved = False - nat_gateway = dict() - states = ['pending', 'failed', 'available', 'deleting', 'deleted'] - err_msg = "" - - while wait_timeout > time.time(): - try: - gws_retrieved, err_msg, nat_gateways = ( - get_nat_gateways( - client, nat_gateway_id=nat_gateway_id, - states=states, check_mode=check_mode - ) - ) - if gws_retrieved and nat_gateways: - nat_gateway = nat_gateways[0] - - if nat_gateway.get('state') == status: - status_achieved = True - break - - elif nat_gateway.get('state') == 'failed': - err_msg = nat_gateway.get('failure_message') - break - - elif nat_gateway.get('state') == 'pending': - if 'failure_message' in nat_gateway: - err_msg = nat_gateway.get('failure_message') - status_achieved = False - break - - else: - time.sleep(polling_increment_secs) - - except botocore.exceptions.ClientError as e: - err_msg = str(e) - - if not status_achieved: - err_msg = "Wait time out reached, while waiting for results" + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) - return status_achieved, err_msg, nat_gateway + return existing_gateways -def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, - check_mode=False): +def gateway_in_subnet_exists(client, module, subnet_id, allocation_id=None): """Retrieve all NAT Gateways for a subnet. Args: + client (botocore.client.EC2): Boto3 client + module: AnsibleAWSModule class instance subnet_id (str): The subnet_id the nat resides in. Kwargs: @@ -420,14 +364,15 @@ def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> subnet_id = 'subnet-1234567' >>> allocation_id = 'eipalloc-1234567' - >>> gateway_in_subnet_exists(client, subnet_id, allocation_id) + >>> gateway_in_subnet_exists(client, module, subnet_id, allocation_id) ( [ { - "nat_gateway_id": "nat-123456789", - "subnet_id": "subnet-123456789", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", "nat_gateway_addresses": [ { "public_ip": "55.55.55.55", @@ -436,9 +381,10 @@ def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, "allocation_id": "eipalloc-1234567" } ], + "nat_gateway_id": "nat-123456789", "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", + "subnet_id": "subnet-123456789", + "tags": {}, "vpc_id": "vpc-1234567" } ], @@ -448,57 +394,53 @@ def gateway_in_subnet_exists(client, subnet_id, allocation_id=None, Returns: Tuple (list, bool) """ + 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 - ) - ) + gws_retrieved = (get_nat_gateways(client, module, subnet_id, states=states)) - if not gws_retrieved: - return gateways, allocation_id_exists - for gw in gws: - for address in gw['nat_gateway_addresses']: - if allocation_id: - if address.get('allocation_id') == allocation_id: - allocation_id_exists = True + if gws_retrieved: + for gw in gws_retrieved: + for address in gw['nat_gateway_addresses']: + if allocation_id: + if address.get('allocation_id') == allocation_id: + allocation_id_exists = True + gateways.append(gw) + else: gateways.append(gw) - else: - gateways.append(gw) return gateways, allocation_id_exists -def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): +def get_eip_allocation_id_by_address(client, module, eip_address): """Release an EIP from your EIP Pool Args: client (botocore.client.EC2): Boto3 client + module: AnsibleAWSModule class instance eip_address (str): The Elastic IP Address of the EIP. - Kwargs: - check_mode (bool): if set to true, do not run anything and - falsify the results. - Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> eip_address = '52.87.29.36' - >>> get_eip_allocation_id_by_address(client, eip_address) + >>> get_eip_allocation_id_by_address(client, module, eip_address) 'eipalloc-36014da3' Returns: Tuple (str, str) """ + params = { 'PublicIps': [eip_address], } allocation_id = None - err_msg = "" + msg = '' try: allocations = client.describe_addresses(aws_retry=True, **params)['Addresses'] + if len(allocations) == 1: allocation = allocations[0] else: @@ -506,135 +448,137 @@ def get_eip_allocation_id_by_address(client, eip_address, check_mode=False): if allocation: if allocation.get('Domain') != 'vpc': - err_msg = ( + msg = ( "EIP {0} is a non-VPC EIP, please allocate a VPC scoped EIP" .format(eip_address) ) else: allocation_id = allocation.get('AllocationId') - else: - err_msg = ( - "EIP {0} does not exist".format(eip_address) - ) - except botocore.exceptions.ClientError as e: - err_msg = str(e) + except is_boto3_error_code('InvalidAddress.Malformed') as e: + module.fail_json(msg='EIP address {0} is invalid.'.format(eip_address)) + except is_boto3_error_code('InvalidAddress.NotFound') as e: # pylint: disable=duplicate-except + msg = ( + "EIP {0} does not exist".format(eip_address) + ) + allocation_id = None + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e) - return allocation_id, err_msg + return allocation_id, msg -def allocate_eip_address(client, check_mode=False): +def allocate_eip_address(client, module): """Release an EIP from your EIP Pool Args: client (botocore.client.EC2): Boto3 client - - Kwargs: - check_mode (bool): if set to true, do not run anything and - falsify the results. + module: AnsibleAWSModule class instance Basic Usage: >>> client = boto3.client('ec2') - >>> allocate_eip_address(client) + >>> module = AnsibleAWSModule(...) + >>> allocate_eip_address(client, module) True Returns: Tuple (bool, str) """ - ip_allocated = False + new_eip = None - err_msg = '' + msg = '' params = { 'Domain': 'vpc', } - if check_mode: + if module.check_mode: ip_allocated = True new_eip = None - return ip_allocated, err_msg, new_eip + return ip_allocated, msg, new_eip try: new_eip = client.allocate_address(aws_retry=True, **params)['AllocationId'] ip_allocated = True - err_msg = 'eipalloc id {0} created'.format(new_eip) - - except botocore.exceptions.ClientError as e: - err_msg = str(e) + msg = 'eipalloc id {0} created'.format(new_eip) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) - return ip_allocated, err_msg, new_eip + return ip_allocated, msg, new_eip -def release_address(client, allocation_id, check_mode=False): +def release_address(client, module, allocation_id): """Release an EIP from your EIP Pool Args: client (botocore.client.EC2): Boto3 client + module: AnsibleAWSModule class instance allocation_id (str): The eip Amazon identifier. - Kwargs: - check_mode (bool): if set to true, do not run anything and - falsify the results. - Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> allocation_id = "eipalloc-123456" - >>> release_address(client, allocation_id) + >>> release_address(client, module, allocation_id) True Returns: Boolean, string """ - err_msg = '' - if check_mode: + msg = '' + + if module.check_mode: return True, '' ip_released = False + try: client.describe_addresses(aws_retry=True, AllocationIds=[allocation_id]) - except botocore.exceptions.ClientError as e: + except is_boto3_error_code('InvalidAllocationID.NotFound') as e: # IP address likely already released # Happens with gateway in 'deleted' state that # still lists associations - return True, str(e) + return True, e + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e) + try: client.release_address(aws_retry=True, AllocationId=allocation_id) ip_released = True - except botocore.exceptions.ClientError as e: - err_msg = str(e) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) - return ip_released, err_msg + return ip_released, msg 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): + wait=False): """Create an Amazon NAT Gateway. Args: client (botocore.client.EC2): Boto3 client - subnet_id (str): The subnet_id the nat resides in. - allocation_id (str): The eip Amazon identifier. + module: AnsibleAWSModule class instance + subnet_id (str): The subnet_id the nat resides in + allocation_id (str): The eip Amazon identifier + tags (dict): Tags to associate to the NAT gateway + purge_tags (bool): If true, remove tags not listed in I(tags) + type: bool Kwargs: - if_exist_do_not_create (bool): if a nat gateway already exists in this - subnet, than do not create another one. - default = False wait (bool): Wait for the nat to be in the deleted state before returning. default = False - wait_timeout (int): Number of seconds to wait, until this timeout is reached. - default = 0 client_token (str): default = None Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> subnet_id = 'subnet-1234567' >>> allocation_id = 'eipalloc-1234567' - >>> create(client, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True, wait_timeout=500) + >>> create(client, module, subnet_id, allocation_id, wait=True) [ true, "", { - "nat_gateway_id": "nat-123456789", - "subnet_id": "subnet-1234567", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", "nat_gateway_addresses": [ { "public_ip": "55.55.55.55", @@ -643,9 +587,10 @@ def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_to "allocation_id": "eipalloc-1234567" } ], + "nat_gateway_id": "nat-123456789", "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", + "subnet_id": "subnet-1234567", + "tags": {}, "vpc_id": "vpc-1234567" } ] @@ -653,73 +598,67 @@ def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_to Returns: Tuple (bool, str, list) """ + params = { 'SubnetId': subnet_id, 'AllocationId': allocation_id } request_time = datetime.datetime.utcnow() changed = False - success = False token_provided = False - err_msg = "" result = {} + msg = '' if client_token: token_provided = True params['ClientToken'] = client_token - if check_mode: - success = True + if module.check_mode: changed = True - return success, changed, err_msg, result + return changed, result, msg try: result = camel_dict_to_snake_dict(client.create_nat_gateway(aws_retry=True, **params)["NatGateway"]) - success = True changed = True create_time = result['create_time'].replace(tzinfo=None) if token_provided and (request_time > create_time): changed = False - elif wait: - success, err_msg, result = ( - wait_for_status( - client, wait_timeout, result['nat_gateway_id'], - 'available', check_mode=check_mode - ) + + elif wait and result.get('state') != 'available': + wait_for_status(client, module, 'nat_gateway_available', result['nat_gateway_id']) + + # Get new result + result = camel_dict_to_snake_dict( + _describe_nat_gateways(client, NatGatewayIds=[result['nat_gateway_id']])[0] ) - if success: - err_msg = ( - 'NAT gateway {0} created'.format(result['nat_gateway_id']) - ) - result['tags'], tags_update_exists = ensure_tags( + + 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 + purge_tags=purge_tags ) - except is_boto3_error_code('IdempotentParameterMismatch'): - err_msg = ( - 'NAT Gateway does not support update and token has already been provided: ' + err_msg + except is_boto3_error_code('IdempotentParameterMismatch') as e: + msg = ( + 'NAT Gateway does not support update and token has already been provided:' + e ) - success = False - changed = False - result = None - except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except - err_msg = to_native(e) - success = False changed = False result = None + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e) - return success, changed, err_msg, result + return changed, result, msg 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): + if_exist_do_not_create=False, wait=False, client_token=None): """Create an Amazon NAT Gateway. Args: client (botocore.client.EC2): Boto3 client - subnet_id (str): The subnet_id the nat resides in. + module: AnsibleAWSModule class instance + subnet_id (str): The subnet_id the nat resides in + tags (dict): Tags to associate to the NAT gateway + purge_tags (bool): If true, remove tags not listed in I(tags) Kwargs: allocation_id (str): The EIP Amazon identifier. @@ -731,22 +670,21 @@ def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, default = False wait (bool): Wait for the nat to be in the deleted state before returning. default = False - wait_timeout (int): Number of seconds to wait, until this timeout is reached. - default = 0 client_token (str): default = None Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> subnet_id = 'subnet-w4t12897' >>> allocation_id = 'eipalloc-36014da3' - >>> pre_create(client, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True, wait_timeout=500) + >>> pre_create(client, module, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True) [ true, "", { - "nat_gateway_id": "nat-03835afb6e31df79b", - "subnet_id": "subnet-w4t12897", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", "nat_gateway_addresses": [ { "public_ip": "52.87.29.36", @@ -755,9 +693,10 @@ def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, "allocation_id": "eipalloc-36014da3" } ], + "nat_gateway_id": "nat-03835afb6e31df79b", "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", + "subnet_id": "subnet-w4t12897", + "tags": {}, "vpc_id": "vpc-w68571b5" } ] @@ -765,105 +704,104 @@ def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, Returns: Tuple (bool, bool, str, list) """ - success = False + changed = False - err_msg = "" + msg = '' results = {} 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, module, subnet_id)) 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) + results['tags'], tags_update_exists = ensure_tags( + client, module, results['nat_gateway_id'], tags, purge_tags + ) if tags_update_exists: - success = True changed = True - return success, changed, err_msg, results + return changed, msg, results - success = True changed = False - err_msg = ( + msg = ( 'NAT Gateway {0} already exists in subnet_id {1}' .format( existing_gateways[0]['nat_gateway_id'], subnet_id ) ) - return success, changed, err_msg, results + return changed, msg, results else: - success, err_msg, allocation_id = ( - allocate_eip_address(client, check_mode=check_mode) + changed, msg, allocation_id = ( + allocate_eip_address(client, module) ) - if not success: - return success, 'False', err_msg, dict() + if not changed: + return changed, msg, dict() elif eip_address or allocation_id: if eip_address and not allocation_id: - allocation_id, err_msg = ( + allocation_id, msg = ( get_eip_allocation_id_by_address( - client, eip_address, check_mode=check_mode + client, module, eip_address ) ) if not allocation_id: - success = False changed = False - return success, changed, err_msg, dict() + return changed, msg, dict() existing_gateways, allocation_id_exists = ( gateway_in_subnet_exists( - client, subnet_id, allocation_id, check_mode=check_mode + client, module, subnet_id, allocation_id ) ) 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) + results['tags'], tags_update_exists = ensure_tags( + client, module, results['nat_gateway_id'], tags, purge_tags + ) + if tags_update_exists: - success = True changed = True - return success, changed, err_msg, results + return changed, msg, results - success = True changed = False - err_msg = ( + msg = ( 'NAT Gateway {0} already exists in subnet_id {1}' .format( existing_gateways[0]['nat_gateway_id'], subnet_id ) ) - return success, changed, err_msg, results + return changed, msg, results - success, changed, err_msg, results = create( - client, module, subnet_id, allocation_id, tags, purge_tags, client_token, - wait, wait_timeout, if_exist_do_not_create, check_mode=check_mode + changed, results, msg = create( + client, module, subnet_id, allocation_id, tags, purge_tags, client_token, wait ) - return success, changed, err_msg, results + return changed, msg, results -def remove(client, nat_gateway_id, wait=False, wait_timeout=0, - release_eip=False, check_mode=False): +def remove(client, module, nat_gateway_id, wait=False, release_eip=False): """Delete an Amazon NAT Gateway. Args: client (botocore.client.EC2): Boto3 client - nat_gateway_id (str): The Amazon nat id. + module: AnsibleAWSModule class instance + nat_gateway_id (str): The Amazon nat id Kwargs: wait (bool): Wait for the nat to be in the deleted state before returning. - wait_timeout (int): Number of seconds to wait, until this timeout is reached. release_eip (bool): Once the nat has been deleted, you can deallocate the eip from the vpc. Basic Usage: >>> client = boto3.client('ec2') + >>> module = AnsibleAWSModule(...) >>> nat_gw_id = 'nat-03835afb6e31df79b' - >>> remove(client, nat_gw_id, wait=True, wait_timeout=500, release_eip=True) + >>> remove(client, module, nat_gw_id, wait=True, release_eip=True) [ true, "", { - "nat_gateway_id": "nat-03835afb6e31df79b", - "subnet_id": "subnet-w4t12897", + "create_time": "2016-03-05T00:33:21.209000+00:00", + "delete_time": "2016-03-05T00:36:37.329000+00:00", "nat_gateway_addresses": [ { "public_ip": "52.87.29.36", @@ -872,9 +810,10 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, "allocation_id": "eipalloc-36014da3" } ], + "nat_gateway_id": "nat-03835afb6e31df79b", "state": "deleted", - "create_time": "2016-03-05T00:33:21.209000+00:00", - "delete_time": "2016-03-05T00:36:37.329000+00:00", + "subnet_id": "subnet-w4t12897", + "tags": {}, "vpc_id": "vpc-w68571b5" } ] @@ -882,75 +821,65 @@ def remove(client, nat_gateway_id, wait=False, wait_timeout=0, Returns: Tuple (bool, str, list) """ + params = { 'NatGatewayId': nat_gateway_id } - success = False changed = False - err_msg = "" results = {} states = ['pending', 'available'] + msg = '' - if check_mode: + if module.check_mode: changed = True - success = True - return success, changed, err_msg, results + return changed, msg, results try: - exist, err_msg, gw = ( + gw_list = ( get_nat_gateways( - client, nat_gateway_id=nat_gateway_id, - states=states, check_mode=check_mode + client, module, nat_gateway_id=nat_gateway_id, + states=states ) ) - if exist and len(gw) == 1: - results = gw[0] - client.delete_nat_gateway(aws_retry=True, **params) + if len(gw_list) == 1: + results = gw_list[0] + client.delete_nat_gateway(aws_retry=True, **params) allocation_id = ( results['nat_gateway_addresses'][0]['allocation_id'] ) changed = True - success = True - err_msg = ( + msg = ( 'NAT gateway {0} is in a deleting state. Delete was successful' .format(nat_gateway_id) ) - if wait: - status_achieved, err_msg, results = ( - wait_for_status( - client, wait_timeout, nat_gateway_id, 'deleted', - check_mode=check_mode - ) - ) - if status_achieved: - err_msg = ( - 'NAT gateway {0} was deleted successfully' - .format(nat_gateway_id) - ) + if wait and results.get('state') != 'deleted': + wait_for_status(client, module, 'nat_gateway_deleted', nat_gateway_id) - except botocore.exceptions.ClientError as e: - err_msg = str(e) + # Get new results + results = camel_dict_to_snake_dict( + _describe_nat_gateways(client, NatGatewayIds=[nat_gateway_id])[0] + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) if release_eip: - eip_released, eip_err = ( - release_address(client, allocation_id, check_mode)) + eip_released, msg = ( + release_address(client, module, allocation_id)) if not eip_released: - err_msg = ( - "{0}: Failed to release EIP {1}: {2}" - .format(err_msg, allocation_id, eip_err) + module.fail_json( + msg="Failed to release EIP {0}: {1}".format(allocation_id, msg) ) - success = False - return success, changed, err_msg, results + return changed, msg, results -def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): +def ensure_tags(client, module, nat_gw_id, tags, purge_tags): final_tags = [] changed = False - if check_mode and nat_gw_id is None: + if module.check_mode and nat_gw_id is None: # We can't describe tags without an EIP id, we might get here when creating a new EIP in check_mode return final_tags, changed @@ -968,8 +897,7 @@ def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): if to_update: try: - if check_mode: - # update tags + if module.check_mode: final_tags.update(to_update) else: client.create_tags( @@ -977,15 +905,13 @@ def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): 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 + if module.check_mode: for key in to_delete: del final_tags[key] else: @@ -994,12 +920,11 @@ def ensure_tags(client, module, nat_gw_id, tags, purge_tags, check_mode): 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): + if not module.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')) @@ -1024,6 +949,7 @@ def main(): tags=dict(required=False, type='dict', aliases=['resource_tags']), purge_tags=dict(default=True, type='bool'), ) + module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, @@ -1035,13 +961,11 @@ def main(): ) state = module.params.get('state').lower() - check_mode = module.check_mode subnet_id = module.params.get('subnet_id') allocation_id = module.params.get('allocation_id') eip_address = module.params.get('eip_address') nat_gateway_id = module.params.get('nat_gateway_id') wait = module.params.get('wait') - wait_timeout = module.params.get('wait_timeout') 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') @@ -1051,36 +975,26 @@ def main(): try: 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') + module.fail_json_aws(e, msg='Failed to connect to AWS.') changed = False - err_msg = '' + msg = '' if state == 'present': - success, changed, err_msg, results = ( + changed, msg, results = ( pre_create( 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 + if_exist_do_not_create, wait, client_token ) ) else: - success, changed, err_msg, results = ( + changed, msg, results = ( remove( - client, nat_gateway_id, wait, wait_timeout, release_eip, - check_mode=check_mode + client, module, nat_gateway_id, wait, release_eip ) ) - if not success: - results = results or {} - module.fail_json( - msg=err_msg, success=success, changed=changed, **results - ) - else: - module.exit_json( - msg=err_msg, success=success, changed=changed, **results - ) + module.exit_json(msg=msg, changed=changed, **results) if __name__ == '__main__': 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 3dcb70a153e..e7e215559f9 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -227,7 +227,6 @@ - '"vpc_id" in create_ngw' - create_ngw.vpc_id == vpc_id - - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" @@ -325,6 +324,8 @@ second_eip_address: "{{ eip_result.public_ip }}" second_allocation_id: "{{ eip_result.allocation_id }}" + + # ============================================================ - name: Create new nat gateway with eip address - CHECK_MODE ec2_vpc_nat_gateway: subnet_id: "{{ subnet_id }}" @@ -900,7 +901,8 @@ - name: Get NAT gateways ec2_vpc_nat_gateway_info: filters: - vpc-id: "{{ vpc_id }}" + vpc-id: "{{ vpc_id }}" + state: ['available'] register: existing_ngws ignore_errors: true From 3ca805ff504943cb94d11808c91b0134728f5a46 Mon Sep 17 00:00:00 2001 From: Alina Buzachis <49211501+alinabuzachis@users.noreply.github.com> Date: Thu, 18 Mar 2021 17:59:02 +0100 Subject: [PATCH 23/31] ec2_vpc_nat_gateway_info: module stabilization (#472) * ec2_vpc_nat_gateway_info: stability * Catches and handles (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) on boto API calls * Add paginator * Document returned data Signed-off-by: Alina Buzachis This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/b0f438b3200b7fc3decdf8b95c70a220ef25bd79 --- plugins/modules/ec2_vpc_nat_gateway_info.py | 102 +++++++++++++++++--- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 7d31eeac993..a9337ecd9f8 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -30,7 +30,6 @@ extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 - ''' EXAMPLES = r''' @@ -69,33 +68,109 @@ ''' RETURN = r''' +changed: + description: True if listing the internet gateways succeeds + type: bool + returned: always + sample: false result: - description: The result of the describe, converted to ansible snake case style. - See http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways for the response. - returned: success + description: + - The result of the describe, converted to ansible snake case style. + - See also U(http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways) + returned: suceess type: list + contains: + create_time: + description: The date and time the NAT gateway was created + returned: always + type: str + sample: "2021-03-11T22:43:25+00:00" + delete_time: + description: The date and time the NAT gateway was deleted + returned: when the NAT gateway has been deleted + type: str + sample: "2021-03-11T22:43:25+00:00" + nat_gateway_addresses: + description: List containing a dictionary with the IP addresses and network interface associated with the NAT gateway + returned: always + type: dict + contains: + allocation_id: + description: The allocation ID of the Elastic IP address that's associated with the NAT gateway + returned: always + type: str + sample: eipalloc-0853e66a40803da76 + network_interface_id: + description: The ID of the network interface associated with the NAT gateway + returned: always + type: str + sample: eni-0a37acdbe306c661c + private_ip: + description: The private IP address associated with the Elastic IP address + returned: always + type: str + sample: 10.0.238.227 + public_ip: + description: The Elastic IP address associated with the NAT gateway + returned: always + type: str + sample: 34.204.123.52 + nat_gateway_id: + description: The ID of the NAT gateway + returned: always + type: str + sample: nat-0c242a2397acf6173 + state: + description: state of the NAT gateway + returned: always + type: str + sample: available + subnet_id: + description: The ID of the subnet in which the NAT gateway is located + returned: always + type: str + sample: subnet-098c447465d4344f9 + vpc_id: + description: The ID of the VPC in which the NAT gateway is located + returned: always + type: str + sample: vpc-02f37f48438ab7d4c + tags: + description: Tags applied to the NAT gateway + returned: always + type: dict + sample: + Tag1: tag1 + Tag_2: tag_2 ''' -import json try: import botocore 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.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 boto3_tag_list_to_ansible_dict +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result -def date_handler(obj): - return obj.isoformat() if hasattr(obj, 'isoformat') else obj +@AWSRetry.jittered_backoff(retries=10) +def _describe_nat_gateways(client, module, **params): + try: + paginator = client.get_paginator('describe_nat_gateways') + return paginator.paginate(**params).build_full_result()['NatGateways'] + except is_boto3_error_code('InvalidNatGatewayID.NotFound'): + module.exit_json(msg="NAT gateway not found.") + except is_boto3_error_code('NatGatewayMalformed'): # pylint: disable=duplicate-except + module.fail_json_aws(msg="NAT gateway id is malformed.") -def get_nat_gateways(client, module, nat_gateway_id=None): +def get_nat_gateways(client, module): params = dict() nat_gateways = list() @@ -103,17 +178,16 @@ def get_nat_gateways(client, module, nat_gateway_id=None): params['NatGatewayIds'] = module.params.get('nat_gateway_ids') try: - result = json.loads(json.dumps(client.describe_nat_gateways(aws_retry=True, **params), default=date_handler)) - except Exception as e: - module.fail_json(msg=to_native(e)) + result = normalize_boto3_result(_describe_nat_gateways(client, module, **params)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, 'Unable to describe NAT gateways.') - for gateway in result['NatGateways']: + for gateway in result: # Turn the boto3 result into ansible_friendly_snaked_names converted_gateway = camel_dict_to_snake_dict(gateway) if 'tags' in converted_gateway: # Turn the boto3 result into ansible friendly tag dictionary converted_gateway['tags'] = boto3_tag_list_to_ansible_dict(converted_gateway['tags']) - nat_gateways.append(converted_gateway) return nat_gateways From 7f6b3e3f137ee3cb941f0752961deb233fe40cca Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 6 May 2021 21:01:46 +0200 Subject: [PATCH 24/31] Update the default module requirements from python 2.6/boto to python 3.6/boto3 This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/c097c55293be0834a2b9d394733ec28965d142d7 --- plugins/modules/ec2_vpc_nat_gateway.py | 1 - plugins/modules/ec2_vpc_nat_gateway_info.py | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 87511fa2582..30a28ca1391 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -13,7 +13,6 @@ short_description: Manage AWS VPC NAT Gateways. description: - Ensure the state of AWS VPC NAT Gateways based on their id, allocation and subnet ids. -requirements: [boto3, botocore] options: state: description: diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index a9337ecd9f8..5acd59a819a 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -13,7 +13,6 @@ description: - Gets various details related to AWS VPC Managed Nat Gateways - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change. -requirements: [ boto3 ] options: nat_gateway_ids: description: From e34ba1d3dc20c972fb0c302f14708bac507c89c6 Mon Sep 17 00:00:00 2001 From: jillr Date: Thu, 29 Apr 2021 21:58:50 +0000 Subject: [PATCH 25/31] Remove shippable references from repo This collection has been operating on Zuul CI for some weeks now This commit was initially merged in https://github.com/ansible-collections/community.aws See: https://github.com/ansible-collections/community.aws/commit/4e0d83c65568a99a24307e37a14e6e0b173c948b --- tests/integration/targets/ec2_vpc_nat_gateway/aliases | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases index e2557d59343..f5291520b8b 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/aliases +++ b/tests/integration/targets/ec2_vpc_nat_gateway/aliases @@ -1,3 +1,2 @@ cloud/aws -shippable/aws/group2 ec2_vpc_nat_gateway_info From 97ce202f91ab183b91856bdec7aac7d07534cf9a Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 26/31] Update runtime --- meta/runtime.yml | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index ddff16a8d69..4f60be535ca 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -58,20 +58,23 @@ action_groups: - ec2_vpc_route_table_facts - ec2_vpc_route_table - ec2_vpc_route_table_info + - ec2_vpc_nat_gateway_facts + - ec2_vpc_nat_gateway + - ec2_vpc_nat_gateway_info plugin_routing: modules: aws_az_facts: deprecation: removal_date: 2022-06-01 warning_text: >- - aws_az_facts was renamed in Ansible 2.9 to aws_az_info. - Please update your tasks. + aws_az_facts was renamed in Ansible 2.9 to aws_az_info. + Please update your tasks. aws_caller_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - aws_caller_facts was renamed in Ansible 2.9 to aws_caller_info. - Please update your tasks. + aws_caller_facts was renamed in Ansible 2.9 to aws_caller_info. + Please update your tasks. cloudformation_facts: deprecation: removal_date: 2021-12-01 @@ -91,44 +94,44 @@ plugin_routing: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_ami_facts was renamed in Ansible 2.9 to ec2_ami_info. - Please update your tasks. + ec2_ami_facts was renamed in Ansible 2.9 to ec2_ami_info. + Please update your tasks. ec2_eni_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_eni_facts was renamed in Ansible 2.9 to ec2_eni_info. - Please update your tasks. + ec2_eni_facts was renamed in Ansible 2.9 to ec2_eni_info. + Please update your tasks. ec2_group_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_group_facts was renamed in Ansible 2.9 to ec2_group_info. - Please update your tasks. + ec2_group_facts was renamed in Ansible 2.9 to ec2_group_info. + Please update your tasks. ec2_snapshot_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_snapshot_facts was renamed in Ansible 2.9 to ec2_snapshot_info. - Please update your tasks. + ec2_snapshot_facts was renamed in Ansible 2.9 to ec2_snapshot_info. + Please update your tasks. ec2_vol_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_vol_facts was renamed in Ansible 2.9 to ec2_vol_info. - Please update your tasks. + ec2_vol_facts was renamed in Ansible 2.9 to ec2_vol_info. + Please update your tasks. ec2_vpc_dhcp_option_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_vpc_dhcp_option_facts was renamed in Ansible 2.9 to - ec2_vpc_dhcp_option_info. Please update your tasks. + ec2_vpc_dhcp_option_facts was renamed in Ansible 2.9 to + ec2_vpc_dhcp_option_info. Please update your tasks. ec2_vpc_net_facts: deprecation: removal_date: 2021-12-01 warning_text: >- - ec2_vpc_net_facts was renamed in Ansible 2.9 to ec2_vpc_net_info. - Please update your tasks. + ec2_vpc_net_facts was renamed in Ansible 2.9 to ec2_vpc_net_info. + Please update your tasks. ec2_vpc_subnet_facts: deprecation: removal_date: 2021-12-01 @@ -154,3 +157,10 @@ plugin_routing: ec2_vpc_route_table_facts was renamed in Ansible 2.9 to ec2_vpc_route_table_info. Please update your tasks. + ec2_vpc_nat_gateway_facts: + deprecation: + removal_date: 2021-12-01 + warning_text: >- + ec2_vpc_nat_gateway_facts was renamed in Ansible 2.9 to + ec2_vpc_nat_gateway_info. + Please update your tasks. From ae80f483d5ff2b5086f87c14879bd9275625ceb8 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 27/31] Update FQDN --- plugins/modules/ec2_vpc_nat_gateway.py | 20 +- plugins/modules/ec2_vpc_nat_gateway_facts.py | 219 ++++++++++++++++++- plugins/modules/ec2_vpc_nat_gateway_info.py | 10 +- 3 files changed, 233 insertions(+), 16 deletions(-) mode change 120000 => 100755 plugins/modules/ec2_vpc_nat_gateway_facts.py diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py index 30a28ca1391..e184b60293c 100644 --- a/plugins/modules/ec2_vpc_nat_gateway.py +++ b/plugins/modules/ec2_vpc_nat_gateway.py @@ -97,7 +97,7 @@ # Note: These examples do not set authentication details, see the AWS Guide for details. - name: Create new nat gateway with client token. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 eip_address: 52.1.1.1 @@ -106,7 +106,7 @@ register: new_nat_gateway - name: Create new nat gateway using an allocation-id. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 allocation_id: eipalloc-12345678 @@ -114,7 +114,7 @@ register: new_nat_gateway - name: Create new nat gateway, using an EIP address and wait for available status. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 eip_address: 52.1.1.1 @@ -123,7 +123,7 @@ register: new_nat_gateway - name: Create new nat gateway and allocate new EIP. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 wait: true @@ -131,7 +131,7 @@ register: new_nat_gateway - name: Create new nat gateway and allocate new EIP if a nat gateway does not yet exist in the subnet. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 wait: true @@ -140,7 +140,7 @@ register: new_nat_gateway - name: Delete nat gateway using discovered nat gateways from facts module. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: absent region: ap-southeast-2 wait: true @@ -150,7 +150,7 @@ loop: "{{ gateways_to_remove.result }}" - name: Delete nat gateway and wait for deleted status. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: absent nat_gateway_id: nat-12345678 wait: true @@ -158,7 +158,7 @@ region: ap-southeast-2 - name: Delete nat gateway and release EIP. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: absent nat_gateway_id: nat-12345678 release_eip: true @@ -167,7 +167,7 @@ region: ap-southeast-2 - name: Create new nat gateway using allocation-id and tags. - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: state: present subnet_id: subnet-12345678 allocation_id: eipalloc-12345678 @@ -178,7 +178,7 @@ register: new_nat_gateway - name: Update tags without purge - community.aws.ec2_vpc_nat_gateway: + amazon.aws.ec2_vpc_nat_gateway: subnet_id: subnet-12345678 allocation_id: eipalloc-12345678 region: ap-southeast-2 diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py deleted file mode 120000 index fd969989977..00000000000 --- a/plugins/modules/ec2_vpc_nat_gateway_facts.py +++ /dev/null @@ -1 +0,0 @@ -ec2_vpc_nat_gateway_info.py \ No newline at end of file diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py new file mode 100755 index 00000000000..f42688144c7 --- /dev/null +++ b/plugins/modules/ec2_vpc_nat_gateway_facts.py @@ -0,0 +1,218 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +module: ec2_vpc_nat_gateway_info +short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. +version_added: 1.0.0 +description: + - Gets various details related to AWS VPC Managed Nat Gateways + - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change. +options: + nat_gateway_ids: + description: + - List of specific nat gateway IDs to fetch details for. + type: list + elements: str + filters: + description: + - A dict of filters to apply. Each dict item consists of a filter key and a filter value. + See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNatGateways.html) + for possible filters. + type: dict +author: Karen Cheng (@Etherdaemon) +extends_documentation_fragment: +- amazon.aws.aws +- amazon.aws.ec2 +''' + +EXAMPLES = r''' +# Simple example of listing all nat gateways +- name: List all managed nat gateways in ap-southeast-2 + amazon.aws.ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + register: all_ngws + +- name: Debugging the result + ansible.builtin.debug: + msg: "{{ all_ngws.result }}" + +- name: Get details on specific nat gateways + amazon.aws.ec2_vpc_nat_gateway_info: + nat_gateway_ids: + - nat-1234567891234567 + - nat-7654321987654321 + region: ap-southeast-2 + register: specific_ngws + +- name: Get all nat gateways with specific filters + amazon.aws.ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + filters: + state: ['pending'] + register: pending_ngws + +- name: Get nat gateways with specific filter + amazon.aws.ec2_vpc_nat_gateway_info: + region: ap-southeast-2 + filters: + subnet-id: subnet-12345678 + state: ['available'] + register: existing_nat_gateways +''' + +RETURN = r''' +changed: + description: True if listing the internet gateways succeeds + type: bool + returned: always + sample: false +result: + description: + - The result of the describe, converted to ansible snake case style. + - See also U(http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways) + returned: suceess + type: list + contains: + create_time: + description: The date and time the NAT gateway was created + returned: always + type: str + sample: "2021-03-11T22:43:25+00:00" + delete_time: + description: The date and time the NAT gateway was deleted + returned: when the NAT gateway has been deleted + type: str + sample: "2021-03-11T22:43:25+00:00" + nat_gateway_addresses: + description: List containing a dictionary with the IP addresses and network interface associated with the NAT gateway + returned: always + type: dict + contains: + allocation_id: + description: The allocation ID of the Elastic IP address that's associated with the NAT gateway + returned: always + type: str + sample: eipalloc-0853e66a40803da76 + network_interface_id: + description: The ID of the network interface associated with the NAT gateway + returned: always + type: str + sample: eni-0a37acdbe306c661c + private_ip: + description: The private IP address associated with the Elastic IP address + returned: always + type: str + sample: 10.0.238.227 + public_ip: + description: The Elastic IP address associated with the NAT gateway + returned: always + type: str + sample: 34.204.123.52 + nat_gateway_id: + description: The ID of the NAT gateway + returned: always + type: str + sample: nat-0c242a2397acf6173 + state: + description: state of the NAT gateway + returned: always + type: str + sample: available + subnet_id: + description: The ID of the subnet in which the NAT gateway is located + returned: always + type: str + sample: subnet-098c447465d4344f9 + vpc_id: + description: The ID of the VPC in which the NAT gateway is located + returned: always + type: str + sample: vpc-02f37f48438ab7d4c + tags: + description: Tags applied to the NAT gateway + returned: always + type: dict + sample: + Tag1: tag1 + Tag_2: tag_2 +''' + + +try: + import botocore +except ImportError: + pass # Handled by AnsibleAWSModule + +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.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 boto3_tag_list_to_ansible_dict +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result + + +@AWSRetry.jittered_backoff(retries=10) +def _describe_nat_gateways(client, module, **params): + try: + paginator = client.get_paginator('describe_nat_gateways') + return paginator.paginate(**params).build_full_result()['NatGateways'] + except is_boto3_error_code('InvalidNatGatewayID.NotFound'): + module.exit_json(msg="NAT gateway not found.") + except is_boto3_error_code('NatGatewayMalformed'): # pylint: disable=duplicate-except + module.fail_json_aws(msg="NAT gateway id is malformed.") + + +def get_nat_gateways(client, module): + params = dict() + nat_gateways = list() + + params['Filter'] = ansible_dict_to_boto3_filter_list(module.params.get('filters')) + params['NatGatewayIds'] = module.params.get('nat_gateway_ids') + + try: + result = normalize_boto3_result(_describe_nat_gateways(client, module, **params)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, 'Unable to describe NAT gateways.') + + for gateway in result: + # Turn the boto3 result into ansible_friendly_snaked_names + converted_gateway = camel_dict_to_snake_dict(gateway) + if 'tags' in converted_gateway: + # Turn the boto3 result into ansible friendly tag dictionary + converted_gateway['tags'] = boto3_tag_list_to_ansible_dict(converted_gateway['tags']) + nat_gateways.append(converted_gateway) + + return nat_gateways + + +def main(): + argument_spec = dict( + filters=dict(default={}, type='dict'), + nat_gateway_ids=dict(default=[], type='list', elements='str'), + ) + + module = AnsibleAWSModule(argument_spec=argument_spec, + supports_check_mode=True,) + if module._name == 'ec2_vpc_nat_gateway_facts': + module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", + date='2021-12-01', collection_name='amazon.aws') + + try: + connection = 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') + + results = get_nat_gateways(connection, module) + + module.exit_json(result=results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py index 5acd59a819a..f42688144c7 100644 --- a/plugins/modules/ec2_vpc_nat_gateway_info.py +++ b/plugins/modules/ec2_vpc_nat_gateway_info.py @@ -34,7 +34,7 @@ EXAMPLES = r''' # Simple example of listing all nat gateways - name: List all managed nat gateways in ap-southeast-2 - community.aws.ec2_vpc_nat_gateway_info: + amazon.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 register: all_ngws @@ -43,7 +43,7 @@ msg: "{{ all_ngws.result }}" - name: Get details on specific nat gateways - community.aws.ec2_vpc_nat_gateway_info: + amazon.aws.ec2_vpc_nat_gateway_info: nat_gateway_ids: - nat-1234567891234567 - nat-7654321987654321 @@ -51,14 +51,14 @@ register: specific_ngws - name: Get all nat gateways with specific filters - community.aws.ec2_vpc_nat_gateway_info: + amazon.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 filters: state: ['pending'] register: pending_ngws - name: Get nat gateways with specific filter - community.aws.ec2_vpc_nat_gateway_info: + amazon.aws.ec2_vpc_nat_gateway_info: region: ap-southeast-2 filters: subnet-id: subnet-12345678 @@ -202,7 +202,7 @@ def main(): supports_check_mode=True,) if module._name == 'ec2_vpc_nat_gateway_facts': module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", - date='2021-12-01', collection_name='community.aws') + date='2021-12-01', collection_name='amazon.aws') try: connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) From 67f4e617f629bbe15e7d44377fc8437301558d47 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 28/31] Remove collection reference inside the tests --- .../ec2_vpc_nat_gateway/defaults/main.yml | 9 +- .../ec2_vpc_nat_gateway/tasks/main.yml | 975 +++++++++--------- 2 files changed, 493 insertions(+), 491 deletions(-) diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml index 6ea912c898e..3794da1020e 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml @@ -1,5 +1,4 @@ ---- -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" +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 e7e215559f9..ec67f0fe0f8 100644 --- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml @@ -1,40 +1,35 @@ ---- - 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 - + aws_access_key: '{{ aws_access_key }}' + aws_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token | default(omit) }}' + region: '{{ aws_region }}' block: - # ============================================================ - name: Create a VPC ec2_vpc_net: - name: "{{ vpc_name }}" + name: '{{ vpc_name }}' state: present - cidr_block: "{{ vpc_cidr }}" + cidr_block: '{{ vpc_cidr }}' register: vpc_result - name: Assert success assert: that: - - vpc_result is successful - - '"vpc" in vpc_result' - - '"cidr_block" in vpc_result.vpc' - - vpc_result.vpc.cidr_block == vpc_cidr - - '"id" in vpc_result.vpc' - - vpc_result.vpc.id.startswith("vpc-") - - '"state" in vpc_result.vpc' - - vpc_result.vpc.state == 'available' - - '"tags" in vpc_result.vpc' + - vpc_result is successful + - '"vpc" in vpc_result' + - '"cidr_block" in vpc_result.vpc' + - vpc_result.vpc.cidr_block == vpc_cidr + - '"id" in vpc_result.vpc' + - vpc_result.vpc.id.startswith("vpc-") + - '"state" in vpc_result.vpc' + - vpc_result.vpc.state == 'available' + - '"tags" in vpc_result.vpc' - - name: "set fact: VPC ID" + - name: 'set fact: VPC ID' set_fact: - vpc_id: "{{ vpc_result.vpc.id }}" + vpc_id: '{{ vpc_result.vpc.id }}' # ============================================================ @@ -48,164 +43,166 @@ - name: Assert success assert: that: - - eip_result is successful - - '"allocation_id" in eip_result' - - 'eip_result.allocation_id.startswith("eipalloc-")' - - '"public_ip" in eip_result' + - eip_result is successful + - '"allocation_id" in eip_result' + - eip_result.allocation_id.startswith("eipalloc-") + - '"public_ip" in eip_result' - - name: "set fact: EIP allocation ID and EIP public IP" + - name: 'set fact: EIP allocation ID and EIP public IP' set_fact: - eip_address: "{{ eip_result.public_ip }}" - allocation_id: "{{ eip_result.allocation_id }}" + 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 }}" + vpc_id: '{{ vpc_id }}' + cidr: '{{ subnet_cidr }}' register: subnet_result - name: Assert success assert: that: - - subnet_result is successful - - '"subnet" in subnet_result' - - '"cidr_block" in subnet_result.subnet' - - subnet_result.subnet.cidr_block == subnet_cidr - - '"id" in subnet_result.subnet' - - subnet_result.subnet.id.startswith("subnet-") - - '"state" in subnet_result.subnet' - - subnet_result.subnet.state == 'available' - - '"tags" in subnet_result.subnet' - - subnet_result.subnet.vpc_id == vpc_id + - subnet_result is successful + - '"subnet" in subnet_result' + - '"cidr_block" in subnet_result.subnet' + - subnet_result.subnet.cidr_block == subnet_cidr + - '"id" in subnet_result.subnet' + - subnet_result.subnet.id.startswith("subnet-") + - '"state" in subnet_result.subnet' + - subnet_result.subnet.state == 'available' + - '"tags" in subnet_result.subnet' + - subnet_result.subnet.vpc_id == vpc_id - - name: "set fact: VPC subnet ID" + - name: 'set fact: VPC subnet ID' set_fact: - subnet_id: "{{ subnet_result.subnet.id }}" + subnet_id: '{{ subnet_result.subnet.id }}' # ============================================================ - name: Search for NAT gateways by subnet (no matches) - CHECK_MODE ec2_vpc_nat_gateway_info: filters: - subnet-id: "{{ subnet_id }}" - state: ['available'] + subnet-id: '{{ subnet_id }}' + state: [available] register: existing_ngws check_mode: yes - name: Assert no NAT gateway found - CHECK_MODE assert: that: - - existing_ngws is successful - - (existing_ngws.result|length) == 0 + - existing_ngws is successful + - (existing_ngws.result|length) == 0 - name: Search for NAT gateways by subnet - no matches ec2_vpc_nat_gateway_info: filters: - subnet-id: "{{ subnet_id }}" - state: ['available'] + subnet-id: '{{ subnet_id }}' + state: [available] register: existing_ngws - name: Assert no NAT gateway found assert: that: - - existing_ngws is successful - - (existing_ngws.result|length) == 0 + - existing_ngws is successful + - (existing_ngws.result|length) == 0 # ============================================================ - name: Create IGW ec2_vpc_igw: - vpc_id: "{{ vpc_id }}" + vpc_id: '{{ vpc_id }}' register: create_igw - name: Assert success assert: that: - - create_igw is successful - - create_igw.gateway_id.startswith("igw-") - - create_igw.vpc_id == vpc_id - - '"gateway_id" in create_igw' + - create_igw is successful + - create_igw.gateway_id.startswith("igw-") + - create_igw.vpc_id == vpc_id + - '"gateway_id" in create_igw' # ============================================================ - name: Create new NAT gateway with eip allocation-id - CHECK_MODE ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + 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 + - create_ngw.changed - name: Create new NAT gateway with eip allocation-id ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' wait: yes register: create_ngw - name: Assert creation happened (expected changed=true) assert: that: - - create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - - - name: "set facts: NAT gateway ID" + - create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + - 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 }}" + nat_gateway_id: '{{ create_ngw.nat_gateway_id }}' + network_interface_id: '{{ create_ngw.nat_gateway_addresses[0].network_interface_id + }}' # ============================================================ - name: Get NAT gateway with specific filters (state and subnet) ec2_vpc_nat_gateway_info: filters: - subnet-id: "{{ subnet_id }}" - state: ['available'] + subnet-id: '{{ subnet_id }}' + state: [available] register: avalaible_ngws - name: Assert success assert: that: - - avalaible_ngws is successful - - avalaible_ngws.result | length == 1 - - '"create_time" in first_ngw' - - '"nat_gateway_addresses" in first_ngw' - - '"nat_gateway_id" in first_ngw' - - first_ngw.nat_gateway_id == nat_gateway_id - - '"state" in first_ngw' - - first_ngw.state == 'available' - - '"subnet_id" in first_ngw' - - first_ngw.subnet_id == subnet_id - - '"tags" in first_ngw' - - '"vpc_id" in first_ngw' - - first_ngw.vpc_id == vpc_id + - avalaible_ngws is successful + - avalaible_ngws.result | length == 1 + - '"create_time" in first_ngw' + - '"nat_gateway_addresses" in first_ngw' + - '"nat_gateway_id" in first_ngw' + - first_ngw.nat_gateway_id == nat_gateway_id + - '"state" in first_ngw' + - first_ngw.state == 'available' + - '"subnet_id" in first_ngw' + - first_ngw.subnet_id == subnet_id + - '"tags" in first_ngw' + - '"vpc_id" in first_ngw' + - first_ngw.vpc_id == vpc_id vars: first_ngw: '{{ avalaible_ngws.result[0] }}' # ============================================================ - - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id - CHECK_MODE + - 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 }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' wait: yes register: create_ngw check_mode: yes @@ -213,95 +210,95 @@ - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE assert: that: - - not create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + - 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 }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' wait: yes register: create_ngw - name: Assert recreation would do nothing (expected changed=false) assert: that: - - not create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - - + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + # ============================================================ - 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 }}" + 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 - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + - 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 }}" + subnet_id: '{{ subnet_id }}' wait: yes register: create_ngw - name: Assert recreation would do nothing (expected changed=false) assert: that: - - not create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + # ============================================================ - name: Allocate a new EIP @@ -310,26 +307,25 @@ reuse_existing_ip_allowed: true tag_name: FREE register: eip_result - + - name: Assert success assert: that: - - eip_result is successful - - '"allocation_id" in eip_result' - - 'eip_result.allocation_id.startswith("eipalloc-")' - - '"public_ip" in eip_result' - - - name: "set fact: EIP allocation ID and EIP public IP" + - eip_result is successful + - '"allocation_id" in eip_result' + - eip_result.allocation_id.startswith("eipalloc-") + - '"public_ip" in eip_result' + - name: 'set fact: EIP allocation ID and EIP public IP' set_fact: - second_eip_address: "{{ eip_result.public_ip }}" - second_allocation_id: "{{ eip_result.allocation_id }}" + second_eip_address: '{{ eip_result.public_ip }}' + second_allocation_id: '{{ eip_result.allocation_id }}' # ============================================================ - name: Create new nat gateway with eip address - CHECK_MODE ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - eip_address: "{{ second_eip_address }}" + subnet_id: '{{ subnet_id }}' + eip_address: '{{ second_eip_address }}' wait: yes register: create_ngw check_mode: yes @@ -337,38 +333,39 @@ - name: Assert creation happened (expected changed=true) - CHECK_MODE assert: that: - - create_ngw.changed - + - create_ngw.changed + - name: Create new NAT gateway with eip address ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - eip_address: "{{ second_eip_address }}" - wait: yes + subnet_id: '{{ subnet_id }}' + eip_address: '{{ second_eip_address }}' + wait: yes register: create_ngw - name: Assert creation happened (expected changed=true) assert: that: - - create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id + - create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id # ============================================================ - - name: Trying this again for idempotency - create new NAT gateway with eip address - CHECK_MODE + - 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: "{{ second_eip_address }}" + subnet_id: '{{ subnet_id }}' + eip_address: '{{ second_eip_address }}' wait: yes register: create_ngw check_mode: yes @@ -376,68 +373,68 @@ - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE assert: that: - - not create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id - name: Trying this again for idempotency - create new NAT gateway with eip address ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - eip_address: "{{ second_eip_address }}" + subnet_id: '{{ subnet_id }}' + eip_address: '{{ second_eip_address }}' wait: yes register: create_ngw - name: Assert recreation would do nothing (expected changed=false) assert: that: - - not create_ngw.changed - - '"create_time" in create_ngw' - - '"nat_gateway_addresses" in create_ngw' - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id + - not create_ngw.changed + - '"create_time" in create_ngw' + - '"nat_gateway_addresses" in create_ngw' + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id # ============================================================ - name: Fetch NAT gateway by ID (list) ec2_vpc_nat_gateway_info: nat_gateway_ids: - - "{{ nat_gateway_id }}" + - '{{ nat_gateway_id }}' register: ngw_info - name: Check NAT gateway exists assert: that: - - ngw_info is successful - - ngw_info.result | length == 1 - - '"create_time" in first_ngw' - - '"nat_gateway_addresses" in first_ngw' - - '"nat_gateway_id" in first_ngw' - - first_ngw.nat_gateway_id == nat_gateway_id - - '"state" in first_ngw' - - first_ngw.state == 'available' - - '"subnet_id" in first_ngw' - - first_ngw.subnet_id == subnet_id - - '"tags" in first_ngw' - - '"vpc_id" in first_ngw' - - first_ngw.vpc_id == vpc_id + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in first_ngw' + - '"nat_gateway_addresses" in first_ngw' + - '"nat_gateway_id" in first_ngw' + - first_ngw.nat_gateway_id == nat_gateway_id + - '"state" in first_ngw' + - first_ngw.state == 'available' + - '"subnet_id" in first_ngw' + - first_ngw.subnet_id == subnet_id + - '"tags" in first_ngw' + - '"vpc_id" in first_ngw' + - first_ngw.vpc_id == vpc_id vars: first_ngw: '{{ ngw_info.result[0] }}' @@ -445,20 +442,20 @@ # ============================================================ - name: Delete NAT gateway - CHECK_MODE ec2_vpc_nat_gateway: - nat_gateway_id: "{{ nat_gateway_id }}" + 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 + - name: Assert state=absent (expected changed=true) - CHECK_MODE assert: that: - - delete_nat_gateway.changed + - delete_nat_gateway.changed - name: Delete NAT gateway ec2_vpc_nat_gateway: - nat_gateway_id: "{{ nat_gateway_id }}" + nat_gateway_id: '{{ nat_gateway_id }}' state: absent wait: yes register: delete_nat_gateway @@ -466,28 +463,28 @@ - name: Assert state=absent (expected changed=true) assert: that: - - delete_nat_gateway.changed - - '"delete_time" in delete_nat_gateway' - - '"nat_gateway_addresses" in delete_nat_gateway' - - '"nat_gateway_id" in delete_nat_gateway' - - delete_nat_gateway.nat_gateway_id == nat_gateway_id - - '"state" in delete_nat_gateway' - - delete_nat_gateway.state == 'deleted' - - '"subnet_id" in delete_nat_gateway' - - delete_nat_gateway.subnet_id == subnet_id - - '"tags" in delete_nat_gateway' - - '"vpc_id" in delete_nat_gateway' - - delete_nat_gateway.vpc_id == vpc_id + - delete_nat_gateway.changed + - '"delete_time" in delete_nat_gateway' + - '"nat_gateway_addresses" in delete_nat_gateway' + - '"nat_gateway_id" in delete_nat_gateway' + - delete_nat_gateway.nat_gateway_id == nat_gateway_id + - '"state" in delete_nat_gateway' + - delete_nat_gateway.state == 'deleted' + - '"subnet_id" in delete_nat_gateway' + - delete_nat_gateway.subnet_id == subnet_id + - '"tags" in delete_nat_gateway' + - '"vpc_id" in delete_nat_gateway' + - delete_nat_gateway.vpc_id == vpc_id # ============================================================ - 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 }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_one: '{{ resource_prefix }} One' - "Tag Two": 'two {{ resource_prefix }}' + Tag Two: two {{ resource_prefix }} wait: yes register: create_ngw check_mode: yes @@ -495,50 +492,50 @@ - name: Assert creation happened (expected changed=true) - CHECK_MODE assert: that: - - create_ngw.changed + - create_ngw.changed - name: Create new NAT gateway with eip allocation-id and tags ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_one: '{{ resource_prefix }} One' - "Tag Two": 'two {{ resource_prefix }}' + Tag Two: two {{ resource_prefix }} wait: yes register: create_ngw - name: Assert creation happened (expected changed=true) assert: that: - - create_ngw.changed - - '"create_time" in create_ngw' - - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id - - '"nat_gateway_id" in create_ngw' - - create_ngw.nat_gateway_id.startswith("nat-") - - '"state" in create_ngw' - - create_ngw.state == 'available' - - '"subnet_id" in create_ngw' - - create_ngw.subnet_id == subnet_id - - '"tags" in create_ngw' - - create_ngw.tags | length == 2 - - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in create_ngw' - - create_ngw.vpc_id == vpc_id - - - name: "set facts: NAT gateway ID" + - create_ngw.changed + - '"create_time" in create_ngw' + - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id + - '"nat_gateway_id" in create_ngw' + - create_ngw.nat_gateway_id.startswith("nat-") + - '"state" in create_ngw' + - create_ngw.state == 'available' + - '"subnet_id" in create_ngw' + - create_ngw.subnet_id == subnet_id + - '"tags" in create_ngw' + - create_ngw.tags | length == 2 + - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in create_ngw' + - create_ngw.vpc_id == vpc_id + + - name: 'set facts: NAT gateway ID' set_fact: - ngw_id: "{{ create_ngw.nat_gateway_id }}" + ngw_id: '{{ create_ngw.nat_gateway_id }}' # ============================================================ - name: Update the tags (no change) - CHECK_MODE ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_one: '{{ resource_prefix }} One' - "Tag Two": 'two {{ resource_prefix }}' + Tag Two: two {{ resource_prefix }} wait: yes register: update_tags_ngw check_mode: yes @@ -546,105 +543,107 @@ - name: assert tag update would do nothing (expected changed=false) - CHECK_MODE assert: that: - - not update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 2 - - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - not update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id - name: Update the tags (no change) ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_one: '{{ resource_prefix }} One' - "Tag Two": 'two {{ resource_prefix }}' + 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 - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 2 - - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - not update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + - # ============================================================ - - name: Gather information about a filtered list of NAT Gateways using tags and state - CHECK_MODE + - name: Gather information about a filtered list of NAT Gateways using tags and + state - CHECK_MODE ec2_vpc_nat_gateway_info: filters: - "tag:Tag Two": 'two {{ resource_prefix }}' - state: ['available'] + tag:Tag Two: two {{ resource_prefix }} + state: [available] register: ngw_info check_mode: yes - name: Assert success - CHECK_MODE assert: that: - - ngw_info is successful - - ngw_info.result | length == 1 - - '"create_time" in second_ngw' - - '"nat_gateway_addresses" in second_ngw' - - '"nat_gateway_id" in second_ngw' - - second_ngw.nat_gateway_id == ngw_id - - '"state" in second_ngw' - - second_ngw.state == 'available' - - '"subnet_id" in second_ngw' - - second_ngw.subnet_id == subnet_id - - '"tags" in second_ngw' - - second_ngw.tags | length == 2 - - '"tag_one" in second_ngw.tags' - - '"Tag Two" in second_ngw.tags' - - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in second_ngw' - - second_ngw.vpc_id == vpc_id + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in second_ngw' + - '"nat_gateway_addresses" in second_ngw' + - '"nat_gateway_id" in second_ngw' + - second_ngw.nat_gateway_id == ngw_id + - '"state" in second_ngw' + - second_ngw.state == 'available' + - '"subnet_id" in second_ngw' + - second_ngw.subnet_id == subnet_id + - '"tags" in second_ngw' + - second_ngw.tags | length == 2 + - '"tag_one" in second_ngw.tags' + - '"Tag Two" in second_ngw.tags' + - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in second_ngw' + - second_ngw.vpc_id == vpc_id vars: second_ngw: '{{ ngw_info.result[0] }}' - - name: Gather information about a filtered list of NAT Gateways using tags and state + - name: Gather information about a filtered list of NAT Gateways using tags and + state ec2_vpc_nat_gateway_info: filters: - "tag:Tag Two": 'two {{ resource_prefix }}' - state: ['available'] + tag:Tag Two: two {{ resource_prefix }} + state: [available] register: ngw_info - name: Assert success assert: that: - - ngw_info is successful - - ngw_info.result | length == 1 - - '"create_time" in second_ngw' - - '"nat_gateway_addresses" in second_ngw' - - '"nat_gateway_id" in second_ngw' - - second_ngw.nat_gateway_id == ngw_id - - '"state" in second_ngw' - - second_ngw.state == 'available' - - '"subnet_id" in second_ngw' - - second_ngw.subnet_id == subnet_id - - '"tags" in second_ngw' - - second_ngw.tags | length == 2 - - '"tag_one" in second_ngw.tags' - - '"Tag Two" in second_ngw.tags' - - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in second_ngw' - - second_ngw.vpc_id == vpc_id + - ngw_info is successful + - ngw_info.result | length == 1 + - '"create_time" in second_ngw' + - '"nat_gateway_addresses" in second_ngw' + - '"nat_gateway_id" in second_ngw' + - second_ngw.nat_gateway_id == ngw_id + - '"state" in second_ngw' + - second_ngw.state == 'available' + - '"subnet_id" in second_ngw' + - second_ngw.subnet_id == subnet_id + - '"tags" in second_ngw' + - second_ngw.tags | length == 2 + - '"tag_one" in second_ngw.tags' + - '"Tag Two" in second_ngw.tags' + - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in second_ngw' + - second_ngw.vpc_id == vpc_id vars: second_ngw: '{{ ngw_info.result[0] }}' @@ -652,11 +651,11 @@ # ============================================================ - name: Update the tags - remove and add - CHECK_MODE ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_three: '{{ resource_prefix }} Three' - "Tag Two": 'two {{ resource_prefix }}' + Tag Two: two {{ resource_prefix }} wait: yes register: update_tags_ngw check_mode: yes @@ -664,79 +663,81 @@ - name: Assert tag update would happen (expected changed=true) - CHECK_MODE assert: that: - - update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 2 - - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id - name: Update the tags - remove and add ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' tags: tag_three: '{{ resource_prefix }} Three' - "Tag Two": 'two {{ resource_prefix }}' + 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 - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 2 - - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 2 + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # ============================================================ - - name: Gather information about a filtered list of NAT Gateways using tags and state (no match) - CHECK_MODE + - name: Gather information about a filtered list of NAT Gateways using tags and + state (no match) - CHECK_MODE ec2_vpc_nat_gateway_info: filters: - "tag:tag_one": '{{ resource_prefix }} One' - state: ['available'] + tag:tag_one: '{{ resource_prefix }} One' + state: [available] register: ngw_info check_mode: yes - name: Assert success - CHECK_MODE assert: that: - - ngw_info is successful - - ngw_info.result | length == 0 + - ngw_info is successful + - ngw_info.result | length == 0 - - name: Gather information about a filtered list of NAT Gateways using tags and state (no match) + - name: Gather information about a filtered list of NAT Gateways using tags and + state (no match) ec2_vpc_nat_gateway_info: filters: - "tag:tag_one": '{{ resource_prefix }} One' - state: ['available'] + tag:tag_one: '{{ resource_prefix }} One' + state: [available] register: ngw_info - name: Assert success assert: that: - - ngw_info is successful - - ngw_info.result | length == 0 + - ngw_info is successful + - ngw_info.result | length == 0 # ============================================================ - 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 }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' purge_tags: no tags: tag_one: '{{ resource_prefix }} One' @@ -747,24 +748,24 @@ - name: Assert tags would be added - CHECK_MODE assert: that: - - update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 3 - - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id - + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 3 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id + - 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 }}" + subnet_id: '{{ subnet_id }}' + allocation_id: '{{ allocation_id }}' purge_tags: no tags: tag_one: '{{ resource_prefix }} One' @@ -774,75 +775,75 @@ - name: Assert tags would be added assert: that: - - update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 3 - - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' - - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' - - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 3 + - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One' + - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three' + - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}' + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # ============================================================ - name: Remove all tags - CHECK_MODE ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + 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 - - '"nat_gateway_id" in delete_tags_ngw' - - delete_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in delete_tags_ngw' - - delete_tags_ngw.subnet_id == subnet_id - - '"tags" in delete_tags_ngw' - - delete_tags_ngw.tags | length == 0 - - '"vpc_id" in delete_tags_ngw' - - delete_tags_ngw.vpc_id == vpc_id + that: + - delete_tags_ngw.changed + - '"nat_gateway_id" in delete_tags_ngw' + - delete_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in delete_tags_ngw' + - delete_tags_ngw.subnet_id == subnet_id + - '"tags" in delete_tags_ngw' + - delete_tags_ngw.tags | length == 0 + - '"vpc_id" in delete_tags_ngw' + - delete_tags_ngw.vpc_id == vpc_id - name: Remove all tags ec2_vpc_nat_gateway: - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + 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 - - '"nat_gateway_id" in delete_tags_ngw' - - delete_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in delete_tags_ngw' - - delete_tags_ngw.subnet_id == subnet_id - - '"tags" in delete_tags_ngw' - - delete_tags_ngw.tags | length == 0 - - '"vpc_id" in delete_tags_ngw' - - delete_tags_ngw.vpc_id == vpc_id + - delete_tags_ngw.changed + - '"nat_gateway_id" in delete_tags_ngw' + - delete_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in delete_tags_ngw' + - delete_tags_ngw.subnet_id == subnet_id + - '"tags" in delete_tags_ngw' + - delete_tags_ngw.tags | length == 0 + - '"vpc_id" in delete_tags_ngw' + - delete_tags_ngw.vpc_id == vpc_id # ============================================================ - 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 }}" + 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 ❤️' + lowercase spaced: "hello cruel world \u2764\uFE0F" + Title Case: "Hello Cruel World \u2764\uFE0F" + CamelCase: "SimpleCamelCase \u2764\uFE0F" + snake_case: "simple_snake_case \u2764\uFE0F" wait: yes register: update_tags_ngw check_mode: yes @@ -850,97 +851,99 @@ - name: Assert tags would be added - CHECK_MODE assert: that: - - update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 4 - - 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 ❤️' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 4 + - "update_tags_ngw.tags[\"lowercase spaced\"] == 'hello cruel world \u2764\uFE0F\ + '" + - "update_tags_ngw.tags[\"Title Case\"] == 'Hello Cruel World \u2764\uFE0F'" + - "update_tags_ngw.tags[\"CamelCase\"] == 'SimpleCamelCase \u2764\uFE0F'" + - "update_tags_ngw.tags[\"snake_case\"] == 'simple_snake_case \u2764\uFE0F'" + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id - name: Update with CamelCase tags ec2_vpc_nat_gateway: if_exist_do_not_create: yes - subnet_id: "{{ subnet_id }}" - allocation_id: "{{ allocation_id }}" + 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 ❤️' + lowercase spaced: "hello cruel world \u2764\uFE0F" + Title Case: "Hello Cruel World \u2764\uFE0F" + CamelCase: "SimpleCamelCase \u2764\uFE0F" + snake_case: "simple_snake_case \u2764\uFE0F" wait: yes register: update_tags_ngw - name: Assert tags would be added assert: that: - - update_tags_ngw.changed - - '"nat_gateway_id" in update_tags_ngw' - - update_tags_ngw.nat_gateway_id == ngw_id - - '"subnet_id" in update_tags_ngw' - - update_tags_ngw.subnet_id == subnet_id - - '"tags" in update_tags_ngw' - - update_tags_ngw.tags | length == 4 - - 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 ❤️' - - '"vpc_id" in update_tags_ngw' - - update_tags_ngw.vpc_id == vpc_id + - update_tags_ngw.changed + - '"nat_gateway_id" in update_tags_ngw' + - update_tags_ngw.nat_gateway_id == ngw_id + - '"subnet_id" in update_tags_ngw' + - update_tags_ngw.subnet_id == subnet_id + - '"tags" in update_tags_ngw' + - update_tags_ngw.tags | length == 4 + - "update_tags_ngw.tags[\"lowercase spaced\"] == 'hello cruel world \u2764\uFE0F\ + '" + - "update_tags_ngw.tags[\"Title Case\"] == 'Hello Cruel World \u2764\uFE0F'" + - "update_tags_ngw.tags[\"CamelCase\"] == 'SimpleCamelCase \u2764\uFE0F'" + - "update_tags_ngw.tags[\"snake_case\"] == 'simple_snake_case \u2764\uFE0F'" + - '"vpc_id" in update_tags_ngw' + - update_tags_ngw.vpc_id == vpc_id # ============================================================ always: - name: Get NAT gateways ec2_vpc_nat_gateway_info: - filters: - vpc-id: "{{ vpc_id }}" - state: ['available'] + filters: + vpc-id: '{{ vpc_id }}' + state: [available] register: existing_ngws ignore_errors: true - name: Tidy up NAT gateway ec2_vpc_nat_gateway: - subnet_id: "{{ item.subnet_id }}" - nat_gateway_id: "{{ item.nat_gateway_id }}" + subnet_id: '{{ item.subnet_id }}' + nat_gateway_id: '{{ item.nat_gateway_id }}' release_eip: yes state: absent wait: yes - with_items: "{{ existing_ngws.result }}" + with_items: '{{ existing_ngws.result }}' ignore_errors: true - name: Delete IGW ec2_vpc_igw: - vpc_id: "{{ vpc_id }}" + vpc_id: '{{ vpc_id }}' state: absent ignore_errors: true - name: Remove subnet ec2_vpc_subnet: state: absent - cidr: "{{ subnet_cidr }}" - vpc_id: "{{ vpc_id }}" + 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 }}" + device_id: '{{ item.nat_gateway_addresses[0].network_interface_id }}' in_vpc: yes - with_items: "{{ existing_ngws.result }}" + with_items: '{{ existing_ngws.result }}' ignore_errors: yes - name: Delete VPC ec2_vpc_net: - name: "{{ vpc_name }}" - cidr_block: "{{ vpc_cidr }}" + name: '{{ vpc_name }}' + cidr_block: '{{ vpc_cidr }}' state: absent purge_cidrs: yes ignore_errors: yes From c700f57d93916fe65181ed4635d6ed2fcefa8445 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 29/31] Add changelog fragment --- changelogs/fragments/migrate_ec2_vpc_nat_gateway.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changelogs/fragments/migrate_ec2_vpc_nat_gateway.yml diff --git a/changelogs/fragments/migrate_ec2_vpc_nat_gateway.yml b/changelogs/fragments/migrate_ec2_vpc_nat_gateway.yml new file mode 100644 index 00000000000..8d45e11dae3 --- /dev/null +++ b/changelogs/fragments/migrate_ec2_vpc_nat_gateway.yml @@ -0,0 +1,10 @@ +major_changes: +- ec2_vpc_nat_gateway_facts - The module has been migrated from the ``community.aws`` + collection. Playbooks using the Fully Qualified Collection Name for this module + should be updated to use ``amazon.aws.ec2_vpc_nat_gateway_info``. +- ec2_vpc_nat_gateway - The module has been migrated from the ``community.aws`` collection. + Playbooks using the Fully Qualified Collection Name for this module should be updated + to use ``amazon.aws.ec2_vpc_nat_gateway``. +- ec2_vpc_nat_gateway_info - The module has been migrated from the ``community.aws`` + collection. Playbooks using the Fully Qualified Collection Name for this module + should be updated to use ``amazon.aws.ec2_vpc_nat_gateway_info``. From 8168cb27b9c2c8a0a0e41e9d3d66fcf48f242db3 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 30/31] Add symlink for facts module --- plugins/modules/ec2_vpc_nat_gateway_facts.py | 219 +------------------ 1 file changed, 1 insertion(+), 218 deletions(-) mode change 100755 => 120000 plugins/modules/ec2_vpc_nat_gateway_facts.py diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py deleted file mode 100755 index f42688144c7..00000000000 --- a/plugins/modules/ec2_vpc_nat_gateway_facts.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/python -# Copyright: Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -DOCUMENTATION = r''' -module: ec2_vpc_nat_gateway_info -short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods. -version_added: 1.0.0 -description: - - Gets various details related to AWS VPC Managed Nat Gateways - - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change. -options: - nat_gateway_ids: - description: - - List of specific nat gateway IDs to fetch details for. - type: list - elements: str - filters: - description: - - A dict of filters to apply. Each dict item consists of a filter key and a filter value. - See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNatGateways.html) - for possible filters. - type: dict -author: Karen Cheng (@Etherdaemon) -extends_documentation_fragment: -- amazon.aws.aws -- amazon.aws.ec2 -''' - -EXAMPLES = r''' -# Simple example of listing all nat gateways -- name: List all managed nat gateways in ap-southeast-2 - amazon.aws.ec2_vpc_nat_gateway_info: - region: ap-southeast-2 - register: all_ngws - -- name: Debugging the result - ansible.builtin.debug: - msg: "{{ all_ngws.result }}" - -- name: Get details on specific nat gateways - amazon.aws.ec2_vpc_nat_gateway_info: - nat_gateway_ids: - - nat-1234567891234567 - - nat-7654321987654321 - region: ap-southeast-2 - register: specific_ngws - -- name: Get all nat gateways with specific filters - amazon.aws.ec2_vpc_nat_gateway_info: - region: ap-southeast-2 - filters: - state: ['pending'] - register: pending_ngws - -- name: Get nat gateways with specific filter - amazon.aws.ec2_vpc_nat_gateway_info: - region: ap-southeast-2 - filters: - subnet-id: subnet-12345678 - state: ['available'] - register: existing_nat_gateways -''' - -RETURN = r''' -changed: - description: True if listing the internet gateways succeeds - type: bool - returned: always - sample: false -result: - description: - - The result of the describe, converted to ansible snake case style. - - See also U(http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways) - returned: suceess - type: list - contains: - create_time: - description: The date and time the NAT gateway was created - returned: always - type: str - sample: "2021-03-11T22:43:25+00:00" - delete_time: - description: The date and time the NAT gateway was deleted - returned: when the NAT gateway has been deleted - type: str - sample: "2021-03-11T22:43:25+00:00" - nat_gateway_addresses: - description: List containing a dictionary with the IP addresses and network interface associated with the NAT gateway - returned: always - type: dict - contains: - allocation_id: - description: The allocation ID of the Elastic IP address that's associated with the NAT gateway - returned: always - type: str - sample: eipalloc-0853e66a40803da76 - network_interface_id: - description: The ID of the network interface associated with the NAT gateway - returned: always - type: str - sample: eni-0a37acdbe306c661c - private_ip: - description: The private IP address associated with the Elastic IP address - returned: always - type: str - sample: 10.0.238.227 - public_ip: - description: The Elastic IP address associated with the NAT gateway - returned: always - type: str - sample: 34.204.123.52 - nat_gateway_id: - description: The ID of the NAT gateway - returned: always - type: str - sample: nat-0c242a2397acf6173 - state: - description: state of the NAT gateway - returned: always - type: str - sample: available - subnet_id: - description: The ID of the subnet in which the NAT gateway is located - returned: always - type: str - sample: subnet-098c447465d4344f9 - vpc_id: - description: The ID of the VPC in which the NAT gateway is located - returned: always - type: str - sample: vpc-02f37f48438ab7d4c - tags: - description: Tags applied to the NAT gateway - returned: always - type: dict - sample: - Tag1: tag1 - Tag_2: tag_2 -''' - - -try: - import botocore -except ImportError: - pass # Handled by AnsibleAWSModule - -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.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 boto3_tag_list_to_ansible_dict -from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code -from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result - - -@AWSRetry.jittered_backoff(retries=10) -def _describe_nat_gateways(client, module, **params): - try: - paginator = client.get_paginator('describe_nat_gateways') - return paginator.paginate(**params).build_full_result()['NatGateways'] - except is_boto3_error_code('InvalidNatGatewayID.NotFound'): - module.exit_json(msg="NAT gateway not found.") - except is_boto3_error_code('NatGatewayMalformed'): # pylint: disable=duplicate-except - module.fail_json_aws(msg="NAT gateway id is malformed.") - - -def get_nat_gateways(client, module): - params = dict() - nat_gateways = list() - - params['Filter'] = ansible_dict_to_boto3_filter_list(module.params.get('filters')) - params['NatGatewayIds'] = module.params.get('nat_gateway_ids') - - try: - result = normalize_boto3_result(_describe_nat_gateways(client, module, **params)) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, 'Unable to describe NAT gateways.') - - for gateway in result: - # Turn the boto3 result into ansible_friendly_snaked_names - converted_gateway = camel_dict_to_snake_dict(gateway) - if 'tags' in converted_gateway: - # Turn the boto3 result into ansible friendly tag dictionary - converted_gateway['tags'] = boto3_tag_list_to_ansible_dict(converted_gateway['tags']) - nat_gateways.append(converted_gateway) - - return nat_gateways - - -def main(): - argument_spec = dict( - filters=dict(default={}, type='dict'), - nat_gateway_ids=dict(default=[], type='list', elements='str'), - ) - - module = AnsibleAWSModule(argument_spec=argument_spec, - supports_check_mode=True,) - if module._name == 'ec2_vpc_nat_gateway_facts': - module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'", - date='2021-12-01', collection_name='amazon.aws') - - try: - connection = 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') - - results = get_nat_gateways(connection, module) - - module.exit_json(result=results) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py new file mode 120000 index 00000000000..fd969989977 --- /dev/null +++ b/plugins/modules/ec2_vpc_nat_gateway_facts.py @@ -0,0 +1 @@ +ec2_vpc_nat_gateway_info.py \ No newline at end of file From 67698fdd570ee5edfa3e1b23664aea6a379b17dd Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Thu, 26 Aug 2021 15:26:28 +0200 Subject: [PATCH 31/31] Update ignore files --- tests/sanity/ignore-2.9.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index 465a1ebcee2..4d111e4b63e 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -20,4 +20,5 @@ plugins/modules/ec2_vpc_net_info.py pylint:ansible-deprecated-no-version # We u plugins/modules/ec2_vpc_route_table_info.py pylint:ansible-deprecated-no-version # We use dates for deprecations, Ansible 2.9 only supports this for compatability plugins/modules/ec2_vpc_subnet_info.py pylint:ansible-deprecated-no-version # We use dates for deprecations, Ansible 2.9 only supports this for compatability plugins/modules/ec2_vpc_endpoint.py pylint:ansible-deprecated-no-version -plugins/modules/ec2_vpc_endpoint_info.py pylint:ansible-deprecated-no-version \ No newline at end of file +plugins/modules/ec2_vpc_endpoint_info.py pylint:ansible-deprecated-no-version +plugins/modules/ec2_vpc_nat_gateway_info.py pylint:ansible-deprecated-no-version