From ab35c45c5d4ca308ec9328a3258567e50427c632 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 25 Oct 2024 16:07:24 +0200 Subject: [PATCH] DNM Promote ec2_vpc_vgw and ec2_vpc_vgw_info modules and tests (#2190) SUMMARY Promote ec2_vpc_vgw and ec2_vpc_vgw_info modules and tests ISSUE TYPE Bugfix Pull Request Docs Pull Request Feature Pull Request New Module Pull Request COMPONENT NAME ADDITIONAL INFORMATION Reviewed-by: Mark Chappell --- changelogs/fragments/migrate_ec2_vpc_vgw.yml | 8 + meta/runtime.yml | 6 +- plugins/modules/ec2_vpc_vgw.py | 545 ------------------ plugins/modules/ec2_vpc_vgw_info.py | 182 ------ tests/integration/targets/ec2_vpc_vgw/aliases | 3 - .../targets/ec2_vpc_vgw/defaults/main.yml | 12 - .../targets/ec2_vpc_vgw/meta/main.yml | 1 - .../targets/ec2_vpc_vgw/tasks/main.yml | 312 ---------- .../targets/ec2_vpc_vgw/tasks/tags.yml | 334 ----------- 9 files changed, 12 insertions(+), 1391 deletions(-) create mode 100644 changelogs/fragments/migrate_ec2_vpc_vgw.yml delete mode 100644 plugins/modules/ec2_vpc_vgw.py delete mode 100644 plugins/modules/ec2_vpc_vgw_info.py delete mode 100644 tests/integration/targets/ec2_vpc_vgw/aliases delete mode 100644 tests/integration/targets/ec2_vpc_vgw/defaults/main.yml delete mode 100644 tests/integration/targets/ec2_vpc_vgw/meta/main.yml delete mode 100644 tests/integration/targets/ec2_vpc_vgw/tasks/main.yml delete mode 100644 tests/integration/targets/ec2_vpc_vgw/tasks/tags.yml diff --git a/changelogs/fragments/migrate_ec2_vpc_vgw.yml b/changelogs/fragments/migrate_ec2_vpc_vgw.yml new file mode 100644 index 00000000000..1f2b0bcc972 --- /dev/null +++ b/changelogs/fragments/migrate_ec2_vpc_vgw.yml @@ -0,0 +1,8 @@ +--- +breaking_changes: + - ec2_vpc_vgw - 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_vgw``. + - ec2_vpc_vgw_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_vgw_info``. diff --git a/meta/runtime.yml b/meta/runtime.yml index fec2385f295..731f7870900 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -111,8 +111,6 @@ action_groups: - ec2_transit_gateway_info - ec2_transit_gateway_vpc_attachment - ec2_transit_gateway_vpc_attachment_info - - ec2_vpc_vgw - - ec2_vpc_vgw_info - ec2_vpc_vpn - ec2_vpc_vpn_info - ec2_win_password @@ -533,6 +531,10 @@ plugin_routing: redirect: amazon.aws.ec2_placement_group_info ec2_launch_template: redirect: amazon.aws.ec2_launch_template + ec2_vpc_vgw: + redirect: amazon.aws.ec2_vpc_vgw + ec2_vpc_vgw_info: + redirect: amazon.aws.ec2_vpc_vgw_info module_utils: route53: redirect: amazon.aws.route53 diff --git a/plugins/modules/ec2_vpc_vgw.py b/plugins/modules/ec2_vpc_vgw.py deleted file mode 100644 index c82236e0570..00000000000 --- a/plugins/modules/ec2_vpc_vgw.py +++ /dev/null @@ -1,545 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -DOCUMENTATION = r""" -module: ec2_vpc_vgw -short_description: Create and delete AWS VPN Virtual Gateways -version_added: 1.0.0 -description: - - Creates AWS VPN Virtual Gateways. - - Deletes AWS VPN Virtual Gateways. - - Attaches Virtual Gateways to VPCs. - - Detaches Virtual Gateways from VPCs. -options: - state: - description: - - V(present) to ensure resource is created. - - V(absent) to remove resource. - default: present - choices: [ "present", "absent"] - type: str - name: - description: - - Name of the VGW to be created or deleted. - type: str - type: - description: - - Type of the virtual gateway to be created. - choices: [ "ipsec.1" ] - default: "ipsec.1" - type: str - vpn_gateway_id: - description: - - VPN gateway ID of an existing virtual gateway. - type: str - vpc_id: - description: - - The ID of a VPC to attach or detach to the VGW. - type: str - asn: - description: - - The BGP ASN on the Amazon side. - type: int - wait_timeout: - description: - - Number of seconds to wait for status during VPC attach and detach. - default: 320 - type: int -notes: - - Support for O(purge_tags) was added in release 4.0.0. -author: - - Nick Aslanidis (@naslanidis) -extends_documentation_fragment: - - amazon.aws.common.modules - - amazon.aws.region.modules - - amazon.aws.tags - - amazon.aws.boto3 -""" - -EXAMPLES = r""" -- name: Create a new VGW attached to a specific VPC - community.aws.ec2_vpc_vgw: - state: present - region: ap-southeast-2 - profile: personal - vpc_id: vpc-12345678 - name: personal-testing - type: ipsec.1 - -- name: Create a new unattached VGW - community.aws.ec2_vpc_vgw: - state: present - region: ap-southeast-2 - profile: personal - name: personal-testing - type: ipsec.1 - tags: - environment: production - owner: ABC - -- name: Remove a new VGW using the name - community.aws.ec2_vpc_vgw: - state: absent - region: ap-southeast-2 - profile: personal - name: personal-testing - type: ipsec.1 - -- name: Remove a new VGW using the vpn_gateway_id - community.aws.ec2_vpc_vgw: - state: absent - region: ap-southeast-2 - profile: personal - vpn_gateway_id: vgw-3a9aa123 - -- name: Detach vpn gateway from VPC - community.aws.ec2_vpc_vgw: - state: present - name: "{{ vgw_name }}" - register: vgw - -- name: Delete vpn gateway - community.aws.ec2_vpc_vgw: - state: absent - vpn_gateway_id: '{{ vgw.vgw.id | default(vgw_id) }}' - ignore_errors: true -""" - -RETURN = r""" -vgw: - description: Information about the virtual private gateway. - returned: success - type: dict - contains: - id: - description: The ID of the virtual private gateway. - type: str - returned: success - sample: "vgw-0123456789abcdef0" - state: - description: The current state of the virtual private gateway. - type: str - returned: success - sample: "available" - tags: - description: A dictionary representing the tags attached to the virtual private gateway. - type: dict - returned: success - sample: { - "Name": "ansible-test-ec2-vpc-vgw", - "Env": "Dev_Test_001" - } - type: - description: The type of VPN connection the virtual private gateway supports. - type: str - returned: success - sample: "ipsec.1" - vpc_id: - description: The ID of the VPC. - type: str - returned: success - sample: "vpc-123456789abcdef01" -""" - -try: - import botocore -except ImportError: - pass # Handled by AnsibleAWSModule - -from typing import Any -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleEC2Error -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import attach_vpn_gateway -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import create_vpn_gateway -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import delete_vpn_gateway -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_vpcs -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_vpn_gateways -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import detach_vpn_gateway -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags -from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry -from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict -from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications -from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter -from ansible_collections.amazon.aws.plugins.module_utils.waiters import wait_for_resource_state - -from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule - - -# AWS uses VpnGatewayLimitExceeded for both 'Too many VGWs' and 'Too many concurrent changes' -# we need to look at the mesage to tell the difference. -class VGWRetry(AWSRetry): - @staticmethod - def status_code_from_exception(error: Any) -> Tuple[str, str]: - return ( - error.response["Error"]["Code"], - error.response["Error"]["Message"], - ) - - @staticmethod - def found(response_code: Union[str, Tuple[str, ...]], catch_extra_error_codes: Optional[List[str]] = None) -> bool: - retry_on = ["The maximum number of mutating objects has been reached."] - - if catch_extra_error_codes: - retry_on.extend(catch_extra_error_codes) - if not isinstance(response_code, tuple): - response_code = (response_code,) - - for code in response_code: - if super(VGWRetry, VGWRetry).found(response_code, catch_extra_error_codes): - return True - - return False - - -def format_vgw_info(vgw: Dict) -> Optional[Dict[str, Any]]: - # to handle check mode case where vgw passed to this function is {} - if not vgw: - return - - vgw_info = { - "id": vgw["VpnGatewayId"], - "type": vgw["Type"], - "state": vgw["State"], - "vpc_id": None, - "tags": dict(), - } - - if vgw["Tags"]: - vgw_info["tags"] = boto3_tag_list_to_ansible_dict(vgw["Tags"]) - - if len(vgw["VpcAttachments"]) != 0 and vgw["VpcAttachments"][0]["State"] == "attached": - vgw_info["vpc_id"] = vgw["VpcAttachments"][0]["VpcId"] - - return vgw_info - - -def wait_for_status(client, module: AnsibleAWSModule, vpn_gateway_id: str, desired_status: str) -> Tuple[bool, Any]: - polling_increment_secs = 15 - max_retries = module.params.get("wait_timeout") // polling_increment_secs - try: - wait_for_resource_state(client, module, "vpn_gateway_exists", VpnGatewayIds=[vpn_gateway_id]) - if desired_status not in ("attached", "detached"): - module.fail_json(msg=f"Unsupported status: {desired_status}") - wait_for_resource_state( - client, - module, - f"vpn_gateway_{desired_status}", - VpnGatewayIds=[vpn_gateway_id], - delay=polling_increment_secs, - max_attempts=max_retries, - ) - - response = find_vgw(client, module, vpn_gateway_id) - status_achieved = response[0]["VpcAttachments"][0]["State"] == desired_status - - except AnsibleEC2Error as e: - module.fail_json_aws(e) - - return status_achieved, response - - -def attach_vgw_to_vpc(client, module: AnsibleAWSModule, vpn_gateway_id: str) -> bool: - if module.check_mode: - return True - response = None - vpc_id = module.params.get("vpc_id") - response = attach_vpn_gateway(client, vpc_id, vpn_gateway_id) - status_achieved, vgw = wait_for_status(client, module, vpn_gateway_id, "attached") - - if not status_achieved: - module.fail_json(msg="Error waiting for VPC to attach to VGW - please check the AWS console") - - return response - - -def detach_vgw(client, module: AnsibleAWSModule, vpn_gateway_id: str, vpc_id: Optional[str] = None) -> bool: - if module.check_mode: - return True - response = None - vpc_id = vpc_id or module.params.get("vpc_id") - - response = detach_vpn_gateway(client, vpc_id, vpn_gateway_id) - - status_achieved, vgw = wait_for_status(client, module, vpn_gateway_id, "detached") - if not status_achieved: - module.fail_json(msg="Error waiting for vpc to detach from vgw - please check the AWS console") - - return response - - -def create_vgw(client, module: AnsibleAWSModule) -> Dict: - if module.check_mode: - return {} - - params = { - "Type": module.params.get("type"), - "TagSpecifications": boto3_tag_specifications( - {**(module.params.get("tags") or {}), "Name": module.params.get("name")}, ["vpn-gateway"] - ), - } - - if module.params.get("asn"): - params["AmazonSideAsn"] = module.params.get("asn") - - try: - create_vgw_result = create_vpn_gateway(client, **params) - get_waiter(client, "vpn_gateway_exists").wait(VpnGatewayIds=[create_vgw_result["VpnGatewayId"]]) - except botocore.exceptions.WaiterError as e: - module.fail_json_aws( - e, msg=f"Failed to wait for Vpn Gateway {create_vgw_result['VpnGatewayId']} to be available" - ) - - return create_vgw_result - - -def delete_vgw(client, module: AnsibleAWSModule, vpn_gateway_id: str) -> Optional[str]: - delete_vpn_gateway(client, vpn_gateway_id) - - # return the deleted VpnGatewayId as this is not included in the above response - result = vpn_gateway_id - return result - - -def find_vpc(client, module: AnsibleAWSModule) -> Optional[Any]: - response = None - params = dict() - vpc_id = module.params.get("vpc_id") - - if vpc_id: - params["VpcIds"] = [vpc_id] - response = describe_vpcs(client, **params) - - return response - - -def find_vgw(client, module: AnsibleAWSModule, vpn_gateway_id: Optional[str] = None) -> List[Dict[str, Any]]: - params = dict() - if vpn_gateway_id: - params["VpnGatewayIds"] = [vpn_gateway_id] - else: - params["Filters"] = [ - {"Name": "type", "Values": [module.params.get("type")]}, - {"Name": "tag:Name", "Values": [module.params.get("name")]}, - ] - if module.params.get("state") == "present": - params["Filters"].append({"Name": "state", "Values": ["pending", "available"]}) - - response = describe_vpn_gateways(client, **params) - - return sorted(response, key=lambda k: k["VpnGatewayId"]) - - -def ensure_vgw_present(client, module: AnsibleAWSModule) -> Tuple[bool, Dict[str, Any]]: - changed = False - vgw = {} - - # Check if provided vgw already exists - existing_vgw = find_vgw(client, module, module.params.get("vpn_gateway_id")) - - # if existing vgw, handle changes as required - if existing_vgw: - changed |= handle_existing_vgw(client, module, existing_vgw[0]) - vgw = find_vgw(client, module, existing_vgw[0]["VpnGatewayId"])[ - 0 - ] # [0] as find_vgw returns list[dict] i.e. [{vgw_info}] as it is possible to have multiple vgw with same names - # if not existing vgw, create new and return - else: - changed = True - if not module.check_mode: - vgw = create_vgw(client, module) - # if vpc_id provided, attach vgw to vpc - if module.params.get("vpc_id"): - attach_vgw_to_vpc(client, module, vgw["VpnGatewayId"]) - vgw = find_vgw(client, module, vgw["VpnGatewayId"])[0] - - return changed, format_vgw_info(vgw) - - -def handle_existing_vgw(client, module: AnsibleAWSModule, existing_vgw: dict) -> bool: - changed = False - vpn_gateway_id = existing_vgw["VpnGatewayId"] - provided_vpc_id = module.params.get("vpc_id") - - # Update tags - desired_tags = module.params.get("tags") - purge_tags = module.params.get("purge_tags") - if desired_tags is None: - desired_tags = dict() - purge_tags = False - tags = dict(Name=module.params.get("name")) - tags.update(desired_tags) - # check_mode is handled by esure_ec2_tags() - changed |= ensure_ec2_tags( - client, module, vpn_gateway_id, resource_type="vpn-gateway", tags=tags, purge_tags=purge_tags - ) - - # Manage VPC attachments - current_vpc_attachments = existing_vgw["VpcAttachments"] - if provided_vpc_id: - # if vgw is attached to a vpc - if current_vpc_attachments and current_vpc_attachments[0]["State"] == "attached": - # if provided vpc is differenct than current vpc, then detach current vpc, attach new vpc - if provided_vpc_id != current_vpc_attachments[0]["VpcId"]: - if module.check_mode: - return True - detach_vgw(client, module, vpn_gateway_id, current_vpc_attachments[0]["VpcId"]) - get_waiter(client, "vpn_gateway_detached").wait(VpnGatewayIds=[vpn_gateway_id]) - attach_vgw_to_vpc(client, module, vpn_gateway_id) - changed = True - # if vgw is not currently attached to a vpc, attach it to provided vpc - else: - if module.check_mode: - return True - attach_vgw_to_vpc(client, module, vpn_gateway_id) - changed = True - # if vpc_id not provided, then detach vgw from vpc - else: - if current_vpc_attachments and current_vpc_attachments[0]["State"] == "attached": - if module.check_mode: - return True - detach_vgw(client, module, vpn_gateway_id, current_vpc_attachments[0]["VpcId"]) - changed = True - - return changed - - -def ensure_vgw_absent(client, module: AnsibleAWSModule) -> Tuple[bool, Optional[str]]: - # If an existing vgw name and type matches our args, then a match is considered to have been - # found and we will take steps to delete it. - - changed = False - params = dict() - result = dict() - deleted_vgw = None - params["Name"] = module.params.get("name") - params["VpcId"] = module.params.get("vpc_id") - params["Type"] = module.params.get("type") - params["Tags"] = module.params.get("tags") - params["VpnGatewayIds"] = module.params.get("vpn_gateway_id") - vpn_gateway_id = module.params.get("vpn_gateway_id") - - # check if a gateway matching our module args already exists - if params["VpnGatewayIds"]: - existing_vgw_with_id = find_vgw(client, module, module.params.get("vpn_gateway_id")) - if existing_vgw_with_id != [] and existing_vgw_with_id[0]["State"] != "deleted": - if module.check_mode: - return True, existing_vgw_with_id[0]["VpnGatewayId"] - existing_vgw = existing_vgw_with_id - if existing_vgw[0]["VpcAttachments"] != [] and existing_vgw[0]["VpcAttachments"][0]["State"] == "attached": - if params["VpcId"]: - if params["VpcId"] != existing_vgw[0]["VpcAttachments"][0]["VpcId"]: - module.fail_json( - msg="The vpc-id provided does not match the vpc-id currently attached - please check the AWS console" - ) - - else: - # detach the vpc from the vgw - detach_vgw(client, module, params["VpnGatewayIds"], params["VpcId"]) - deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"]) - changed = True - - else: - # attempt to detach any attached vpcs - for vpc in existing_vgw[0]["VpcAttachments"]: - detach_vgw(client, module, vpn_gateway_id, vpc["VpcId"]) - deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"]) - changed = True - - else: - # no vpc's are attached so attempt to delete the vgw - deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"]) - changed = True - - else: - changed = False - deleted_vgw = "Nothing to do" - - else: - # Check that a name and type argument has been supplied if no vgw-id - if not module.params.get("name") or not module.params.get("type"): - module.fail_json(msg="A name and type is required when no vgw-id and a status of 'absent' is supplied") - - existing_vgw = find_vgw(client, module) - if existing_vgw != [] and existing_vgw[0]["State"] != "deleted": - vpn_gateway_id = existing_vgw[0]["VpnGatewayId"] - if existing_vgw[0]["VpcAttachments"] != [] and existing_vgw[0]["VpcAttachments"][0]["State"] == "attached": - if params["VpcId"]: - if params["VpcId"] != existing_vgw[0]["VpcAttachments"][0]["VpcId"]: - module.fail_json( - msg="The vpc-id provided does not match the vpc-id currently attached - please check the AWS console" - ) - - else: - if module.check_mode: - return True, None - # detach the vpc from the vgw - detach_vgw(client, module, vpn_gateway_id, params["VpcId"]) - - # now that the vpc has been detached, delete the vgw - deleted_vgw = delete_vgw(client, module, vpn_gateway_id) - changed = True - - else: - if module.check_mode: - return True, vpn_gateway_id - # attempt to detach any attached vpcs - vpc_to_detach = existing_vgw[0]["VpcAttachments"][0]["VpcId"] - detach_vgw(client, module, vpn_gateway_id, vpc_to_detach) - changed = True - - # now that the vpc has been detached, delete the vgw - deleted_vgw = delete_vgw(client, module, vpn_gateway_id) - - else: - if module.check_mode: - return True, vpn_gateway_id - # no vpc's are attached so attempt to delete the vgw - deleted_vgw = delete_vgw(client, module, vpn_gateway_id) - changed = True - - else: - changed = False - deleted_vgw = None - - result = deleted_vgw - return changed, result - - -def main(): - argument_spec = dict( - state=dict(default="present", choices=["present", "absent"]), - name=dict(), - vpn_gateway_id=dict(), - vpc_id=dict(), - asn=dict(type="int"), - wait_timeout=dict(type="int", default=320), - type=dict(default="ipsec.1", choices=["ipsec.1"]), - tags=dict(default=None, required=False, type="dict", aliases=["resource_tags"]), - purge_tags=dict(default=True, type="bool"), - ) - module = AnsibleAWSModule( - argument_spec=argument_spec, - required_if=[["state", "present", ["name"]]], - supports_check_mode=True, - ) - state = module.params.get("state").lower() - - client = module.client("ec2") - - if state == "present": - (changed, results) = ensure_vgw_present(client, module) - else: - (changed, results) = ensure_vgw_absent(client, module) - module.exit_json(changed=changed, vgw=results) - - -if __name__ == "__main__": - main() diff --git a/plugins/modules/ec2_vpc_vgw_info.py b/plugins/modules/ec2_vpc_vgw_info.py deleted file mode 100644 index 79576acf288..00000000000 --- a/plugins/modules/ec2_vpc_vgw_info.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -DOCUMENTATION = r""" ---- -module: ec2_vpc_vgw_info -version_added: 1.0.0 -short_description: Gather information about virtual gateways in AWS -description: - - Gather information about virtual gateways (VGWs) in AWS. -options: - 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_DescribeVpnGateways.html) for possible filters. - type: dict - default: {} - vpn_gateway_ids: - description: One or more virtual private gateway IDs. - type: list - elements: str -author: - - "Nick Aslanidis (@naslanidis)" -extends_documentation_fragment: - - amazon.aws.common.modules - - amazon.aws.region.modules - - amazon.aws.boto3 -""" - -EXAMPLES = r""" -# Note: These examples do not set authentication details, see the AWS Guide for details. - -- name: Gather information about all virtual gateways for an account or profile - community.aws.ec2_vpc_vgw_info: - region: ap-southeast-2 - -- name: Gather information about a filtered list of Virtual Gateways - community.aws.ec2_vpc_vgw_info: - region: ap-southeast-2 - profile: production - filters: - "tag:Name": "main-virt-gateway" - -- name: Gather information about a specific virtual gateway by VpnGatewayIds - community.aws.ec2_vpc_vgw_info: - region: ap-southeast-2 - profile: production - vpn_gateway_ids: vgw-c432f6a7 -""" - -RETURN = r""" -virtual_gateways: - description: Information about one or more virtual private gateways. - returned: always - type: list - elements: dict - contains: - vpn_gateway_id: - description: The ID of the virtual private gateway. - type: str - returned: success - example: "vgw-0123456789abcdef0" - state: - description: Informtion about the current state of the virtual private gateway. - type: str - returned: success - example: "available" - type: - description: Information about type of VPN connection the virtual private gateway supports. - type: str - returned: success - example: "ipsec.1" - vpc_attachments: - description: Information about the VPCs attached to the virtual private gateway. - type: list - elements: dict - returned: success - contains: - state: - description: The current state of the attachment. - type: str - returned: success - example: "available" - vpc_id: - description: The ID of the VPC. - type: str - returned: success - example: "vpc-12345678901234567" - tags: - description: - - A list of dictionaries representing the tags attached to the virtual private gateway. - - Represents the same details as RV(virtual_gateways.resource_tags). - type: list - elements: dict - returned: success - contains: - key: - description: The key of the tag. - type: str - returned: success - example: "MyKey" - value: - description: The value of the tag. - type: str - returned: success - example: "MyValue" - resource_tags: - description: - - A dictionary representing the tags attached to the VGW. - - Represents the same details as RV(virtual_gateways.tags). - type: dict - returned: success - example: { - "MyKey": "MyValue", - "Env": "Dev_Test_01" - } -""" - -from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict - -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleEC2Error -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_vpn_gateways -from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict -from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list - -from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule - - -def get_virtual_gateway_info(virtual_gateway): - tags = virtual_gateway.get("Tags", []) - resource_tags = boto3_tag_list_to_ansible_dict(tags) - virtual_gateway_info = dict( - VpnGatewayId=virtual_gateway["VpnGatewayId"], - State=virtual_gateway["State"], - Type=virtual_gateway["Type"], - VpcAttachments=virtual_gateway["VpcAttachments"], - Tags=tags, - ResourceTags=resource_tags, - ) - return virtual_gateway_info - - -def list_virtual_gateways(client, module): - params = dict() - vpn_gateway_ids = module.params.get("vpn_gateway_ids") - filters = module.params.get("filters") - - if filters: - params["Filters"] = ansible_dict_to_boto3_filter_list(filters) - if vpn_gateway_ids: - params["VpnGatewayIds"] = vpn_gateway_ids - - try: - all_virtual_gateways = describe_vpn_gateways(client, **params) - except AnsibleEC2Error as e: - module.fail_json_aws_error(e) - - return [ - camel_dict_to_snake_dict(get_virtual_gateway_info(vgw), ignore_list=["ResourceTags"]) - for vgw in all_virtual_gateways - ] - - -def main(): - argument_spec = dict( - filters=dict(type="dict", default=dict()), - vpn_gateway_ids=dict(type="list", default=None, elements="str"), - ) - - module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) - - connection = module.client("ec2") - results = list_virtual_gateways(connection, module) - - module.exit_json(virtual_gateways=results) - - -if __name__ == "__main__": - main() diff --git a/tests/integration/targets/ec2_vpc_vgw/aliases b/tests/integration/targets/ec2_vpc_vgw/aliases deleted file mode 100644 index 9daebe59222..00000000000 --- a/tests/integration/targets/ec2_vpc_vgw/aliases +++ /dev/null @@ -1,3 +0,0 @@ -cloud/aws - -ec2_vpc_vgw_info diff --git a/tests/integration/targets/ec2_vpc_vgw/defaults/main.yml b/tests/integration/targets/ec2_vpc_vgw/defaults/main.yml deleted file mode 100644 index b10650336c4..00000000000 --- a/tests/integration/targets/ec2_vpc_vgw/defaults/main.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -vpc_name: '{{ resource_prefix }}-ec2-vpc-vgw' -vgw_name: '{{ resource_prefix }}-ec2-vpc-vgw' -subnet_name: '{{ resource_prefix }}-ec2-vpc-vgw' -vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16' -subnet_1: '10.{{ 256 | random(seed=resource_prefix) }}.1.0/24' -subnet_2: '10.{{ 256 | random(seed=resource_prefix) }}.2.0/24' -subnet_3: '10.{{ 256 | random(seed=resource_prefix) }}.3.0/24' -subnet_4: '10.{{ 256 | random(seed=resource_prefix) }}.4.0/24' - -vpc_ipv6_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.5.0/25' -vpc_ipv6_name: '{{ vpc_name }}-ipv6' diff --git a/tests/integration/targets/ec2_vpc_vgw/meta/main.yml b/tests/integration/targets/ec2_vpc_vgw/meta/main.yml deleted file mode 100644 index 32cf5dda7ed..00000000000 --- a/tests/integration/targets/ec2_vpc_vgw/meta/main.yml +++ /dev/null @@ -1 +0,0 @@ -dependencies: [] diff --git a/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml b/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml deleted file mode 100644 index fefc4b18861..00000000000 --- a/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml +++ /dev/null @@ -1,312 +0,0 @@ ---- -- name: 'ec2_vpc_vgw integration tests' - collections: - - amazon.aws - module_defaults: - group/aws: - access_key: '{{ aws_access_key }}' - secret_key: '{{ aws_secret_key }}' - session_token: '{{ security_token | default(omit) }}' - region: '{{ aws_region }}' - block: - - # ============================================================ - - name: Create a VPC - amazon.aws.ec2_vpc_net: - name: "{{ vpc_name }}-{{ item }}" - state: present - cidr_block: "{{ vpc_cidr }}" - tags: - Description: "Created by ansible-test for IGW tests" - register: vpc_result - loop: [1, 2] - - - name: Use set fact for vpc ids - ansible.builtin.set_fact: - vpc_id_1: '{{ vpc_result.results.0.vpc.id }}' - vpc_id_2: '{{ vpc_result.results.1.vpc.id }}' - - # ============================================================ - - name: Create vpn gateway and attach it to vpc - check_mode - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_1 }}' - name: "{{ vgw_name }}" - register: vgw_check_mode - check_mode: true - - - name: Assert check_mode result - no vgw creation - ansible.builtin.assert: - that: - - vgw_check_mode.changed - - not vgw_check_mode.failed - - "'ec2:CreateVpnGateway' not in vgw_check_mode.resource_actions" - - "'ec2:AttachVpnGateway' not in vgw_check_mode.resource_actions" - - - name: Create vpn gateway and attach it to vpc - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_1 }}' - name: "{{ vgw_name }}" - register: vgw - - - name: Use set fact for vgw ids - ansible.builtin.set_fact: - vgw_id: '{{ vgw.vgw.id }}' - - - name: Assert result - vgw creation - ansible.builtin.assert: - that: - - vgw.changed - - vgw.vgw.vpc_id == vpc_id_1 - - vgw.vgw.tags.Name == vgw_name - - - name: Test idempotence - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_1 }}' - name: "{{ vgw_name }}" - register: vgw - - - name: Assert idempotence result - no change - ansible.builtin.assert: - that: - - not vgw.changed - - vgw.vgw.id == vgw_id - - # ============================================================ - - name: Attach vpn gateway to the other VPC - check_mode - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_2 }}' - name: "{{ vgw_name }}" - register: vgw_check_mode - check_mode: true - - - name: Assert check_mode result - no create/attach/detach - ansible.builtin.assert: - that: - - vgw_check_mode.changed - - not vgw_check_mode.failed - - "'ec2:CreateVpnGateway' not in vgw_check_mode.resource_actions" - - "'ec2:AttachVpnGateway' not in vgw_check_mode.resource_actions" - - "'ec2:DetachVpnGateway' not in vgw_check_mode.resource_actions" - - - name: Attach vpn gateway to the other VPC - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_2 }}' - name: "{{ vgw_name }}" - register: vgw - - - name: Assert attach result - ansible.builtin.assert: - that: - - vgw.changed - - vgw.vgw.id == vgw_id - - vgw.vgw.vpc_id == vpc_id_2 - - - name: Attach vpn gateway to the other VPC - idempotency - community.aws.ec2_vpc_vgw: - state: present - vpc_id: '{{ vpc_id_2 }}' - name: "{{ vgw_name }}" - register: vgw - - - name: Assert idempotency result - no change - ansible.builtin.assert: - that: - - not vgw.changed - - not vgw.failed - - "'ec2:CreateVpnGateway' not in vgw_check_mode.resource_actions" - - "'ec2:AttachVpnGateway' not in vgw_check_mode.resource_actions" - - "'ec2:DetachVpnGateway' not in vgw_check_mode.resource_actions" - - # ============================================================ - - - name: Get VPC VGW facts by ID (CHECK) - community.aws.ec2_vpc_vgw_info: - vpn_gateway_ids: ['{{ vgw_id }}'] - register: vgw_info - check_mode: True - - - name: Verify expected facts - vars: - vgw_details: '{{ vgw_info.virtual_gateways[0] }}' - attach_1_description: - state: 'detached' - vpc_id: '{{ vpc_id_1 }}' - attach_2_description: - state: 'attached' - vpc_id: '{{ vpc_id_2 }}' - ansible.builtin.assert: - that: - - vgw_info.virtual_gateways | length == 1 - - '"resource_tags" in vgw_details' - - '"state" in vgw_details' - - '"tags" in vgw_details' - - '"type" in vgw_details' - - '"vpc_attachments" in vgw_details' - - '"vpn_gateway_id" in vgw_details' - - vgw_details.vpn_gateway_id == vgw_id - - vgw_details.type == 'ipsec.1' - - vgw_details.state == 'available' - - '"Name" in vgw_details.resource_tags' - - vgw_details.resource_tags.Name == vgw_name - - ( - attach_1_description in vgw_details.vpc_attachments - and - vgw_details.vpc_attachments | length == 2 - ) or ( vgw_details.vpc_attachments | length == 1 ) - - attach_2_description in vgw_details.vpc_attachments - - - name: Get VPC VGW facts by Tag - community.aws.ec2_vpc_vgw_info: - filters: - "tag:Name": "{{ vgw_name }}" - register: vgw_info - - - name: Verify expected facts - vars: - vgw_details: '{{ vgw_info.virtual_gateways[0] }}' - attach_1_description: - state: 'detached' - vpc_id: '{{ vpc_id_1 }}' - attach_2_description: - state: 'attached' - vpc_id: '{{ vpc_id_2 }}' - ansible.builtin.assert: - that: - - vgw_info.virtual_gateways | length == 1 - - '"resource_tags" in vgw_details' - - '"state" in vgw_details' - - '"tags" in vgw_details' - - '"type" in vgw_details' - - '"vpc_attachments" in vgw_details' - - '"vpn_gateway_id" in vgw_details' - - vgw_details.vpn_gateway_id == vgw_id - - vgw_details.type == 'ipsec.1' - - vgw_details.state == 'available' - - '"Name" in vgw_details.resource_tags' - - vgw_details.resource_tags.Name == vgw_name - - ( - attach_1_description in vgw_details.vpc_attachments - and - vgw_details.vpc_attachments | length == 2 - ) or ( vgw_details.vpc_attachments | length == 1 ) - - attach_2_description in vgw_details.vpc_attachments - - # ============================================================ - - - name: Get all VGWs - community.aws.ec2_vpc_vgw_info: - register: vgw_info - - - name: Verify test VGW is in the results - vars: - vgw_id_list: '{{ vgw_info.virtual_gateways | map(attribute="vpn_gateway_id") | list }}' - ansible.builtin.assert: - that: - - vgw_id in vgw_id_list - - # ============================================================ - - name: Detach vpn gateway - check_mode - community.aws.ec2_vpc_vgw: - state: present - name: "{{ vgw_name }}" - register: vgw_check_mode - check_mode: true - - - name: Assert check_mode results - no detach action - ansible.builtin.assert: - that: - - vgw_check_mode.changed - - not vgw_check_mode.failed - - "'ec2:DetachVpcGateway' not in vgw_check_mode.resource_actions" - - - name: Detach vpn gateway - community.aws.ec2_vpc_vgw: - state: present - name: "{{ vgw_name }}" - register: vgw - - - name: Assert results - ansible.builtin.assert: - that: - - vgw.changed - - not vgw.vgw.vpc_id - - - name: Test idempotence - community.aws.ec2_vpc_vgw: - state: present - name: "{{ vgw_name }}" - register: vgw - - - name: Assert idempotency result - no change - ansible.builtin.assert: - that: - - not vgw.changed - - # ============================================================ - - - include_tasks: 'tags.yml' - - # ============================================================ - - - name: Delete vpn gateway - check_mode - community.aws.ec2_vpc_vgw: - state: absent - name: "{{ vgw_name }}" - register: vgw_check_mode - check_mode: true - - - name: Assert check_mode result - no delete action - ansible.builtin.assert: - that: - - vgw_check_mode.changed - - not vgw_check_mode.failed - - "'ec2:DeleteVpnGateway' not in vgw_check_mode.resource_actions" - - - name: Delete vpn gateway - community.aws.ec2_vpc_vgw: - state: absent - name: "{{ vgw_name }}" - register: vgw - - - name: Assert result - ansible.builtin.assert: - that: - - vgw.changed - - - name: Test idempotence - community.aws.ec2_vpc_vgw: - state: absent - name: "{{ vgw_name }}" - register: vgw - - - name: Assert idempotency result - no change - ansible.builtin.assert: - that: - - not vgw.changed - - always: - - - ansible.builtin.debug: msg="Removing test dependencies" - - - name: Delete vpn gateway - community.aws.ec2_vpc_vgw: - state: absent - vpn_gateway_id: '{{ vgw.vgw.id | default(vgw_id) }}' - ignore_errors: true - - - name: Delete vpc - amazon.aws.ec2_vpc_net: - name: "{{ vpc_name }}-{{ item }}" - state: absent - cidr_block: "{{ vpc_cidr }}" - loop: [1, 2] - register: result - retries: 10 - delay: 5 - until: result is not failed - ignore_errors: true diff --git a/tests/integration/targets/ec2_vpc_vgw/tasks/tags.yml b/tests/integration/targets/ec2_vpc_vgw/tasks/tags.yml deleted file mode 100644 index 816e9216813..00000000000 --- a/tests/integration/targets/ec2_vpc_vgw/tasks/tags.yml +++ /dev/null @@ -1,334 +0,0 @@ -- vars: - first_tags: - 'Key with Spaces': Value with spaces - CamelCaseKey: CamelCaseValue - pascalCaseKey: pascalCaseValue - snake_case_key: snake_case_value - second_tags: - 'New Key with Spaces': Value with spaces - NewCamelCaseKey: CamelCaseValue - newPascalCaseKey: pascalCaseValue - new_snake_case_key: snake_case_value - third_tags: - 'Key with Spaces': Value with spaces - CamelCaseKey: CamelCaseValue - pascalCaseKey: pascalCaseValue - snake_case_key: snake_case_value - 'New Key with Spaces': Updated Value with spaces - final_tags: - 'Key with Spaces': Value with spaces - CamelCaseKey: CamelCaseValue - pascalCaseKey: pascalCaseValue - snake_case_key: snake_case_value - 'New Key with Spaces': Updated Value with spaces - NewCamelCaseKey: CamelCaseValue - newPascalCaseKey: pascalCaseValue - new_snake_case_key: snake_case_value - name_tags: - Name: '{{ vgw_name }}' - module_defaults: - community.aws.ec2_vpc_vgw: - name: '{{ vgw_name }}' - ec2_vpc_vgw_info: - vpn_gateway_ids: ['{{ vgw_id }}'] - block: - - # ============================================================ - - - name: Add tags - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ first_tags }}' - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would change - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw is not failed - - "'ec2:CreateTags' not in tag_vgw.resource_actions" - - - name: Add tags - community.aws.ec2_vpc_vgw: - tags: '{{ first_tags }}' - state: 'present' - register: tag_vgw - - - name: Get VPC VGW facts - ec2_vpc_vgw_info: {} - register: tag_vgw_info - - - name: Verify the tags were added - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( first_tags | combine(name_tags) ) - - - name: Add tags - IDEMPOTENCY - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ first_tags }}' - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would not change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - - name: Add tags - IDEMPOTENCY - community.aws.ec2_vpc_vgw: - tags: '{{ first_tags }}' - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: {} - register: tag_vgw_info - - - name: Verify no change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( first_tags | combine(name_tags) ) - - # ============================================================ - - - name: Get VPC VGW facts by filter - ec2_vpc_vgw_info: - filters: - 'tag:Name': '{{ vgw_name }}' - vpn_gateway_ids: '{{ omit }}' - register: tag_vgw_info - - - name: Assert the facts are the same as before - ansible.builtin.assert: - that: - - tag_vgw_info.virtual_gateways | length == 1 - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - # ============================================================ - - - name: Modify tags with purge - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ second_tags }}' - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would change - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - - name: Modify tags with purge - community.aws.ec2_vpc_vgw: - tags: '{{ second_tags }}' - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify the tags were added - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( second_tags | combine(name_tags) ) - - - name: Modify tags with purge - IDEMPOTENCY - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ second_tags }}' - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would not change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - - name: Modify tags with purge - IDEMPOTENCY - community.aws.ec2_vpc_vgw: - tags: '{{ second_tags }}' - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify no change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( second_tags | combine(name_tags) ) - - # ============================================================ - - - name: Modify tags without purge - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ third_tags }}' - state: 'present' - purge_tags: False - register: tag_vgw - check_mode: True - - - name: Assert would change - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - - name: Modify tags without purge - community.aws.ec2_vpc_vgw: - tags: '{{ third_tags }}' - state: 'present' - purge_tags: False - register: tag_vgw - - name: et VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify the tags were added - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( final_tags | combine(name_tags) ) - - - name: Modify tags without purge - IDEMPOTENCY - check_mode - community.aws.ec2_vpc_vgw: - tags: '{{ third_tags }}' - state: 'present' - purge_tags: False - register: tag_vgw - check_mode: True - - - name: Assert would not change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - - name: Modify tags without purge - IDEMPOTENCY - community.aws.ec2_vpc_vgw: - tags: '{{ third_tags }}' - state: 'present' - purge_tags: False - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify no change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( final_tags | combine(name_tags) ) - - # ============================================================ - - - name: No change to tags without setting tags - check_mode - community.aws.ec2_vpc_vgw: - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - - name: No change to tags without setting tags - community.aws.ec2_vpc_vgw: - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify the tags were added - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == ( final_tags | combine(name_tags) ) - - # ============================================================ - - - name: Remove non name tags - check_mode - community.aws.ec2_vpc_vgw: - tags: {} - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would change - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - - name: Remove non name tags - community.aws.ec2_vpc_vgw: - tags: {} - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify the tags were added - ansible.builtin.assert: - that: - - tag_vgw is changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == name_tags - - - name: Remove non name tags - IDEMPOTENCY - check_mode - community.aws.ec2_vpc_vgw: - tags: {} - state: 'present' - register: tag_vgw - check_mode: True - - - name: Assert would not change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - - name: Remove non name tags - IDEMPOTENCY - community.aws.ec2_vpc_vgw: - tags: {} - state: 'present' - register: tag_vgw - - name: Get VPC VGW facts - ec2_vpc_vgw_info: - register: tag_vgw_info - - - name: Verify no change - ansible.builtin.assert: - that: - - tag_vgw is not changed - - tag_vgw.vgw.id == vgw_id - - tag_vgw_info.virtual_gateways[0].vpn_gateway_id == vgw_id - - tag_vgw_info.virtual_gateways[0].resource_tags == name_tags