From d74c698560cffac89c1afacc1c3ff9c490f861b9 Mon Sep 17 00:00:00 2001 From: GomathiselviS Date: Thu, 13 Jul 2023 10:31:56 +0530 Subject: [PATCH 1/2] Add transit-gateway-id parameter to ec2_vpc_vpn module (#1877) Add transit-gateway-id parameter to ec2_vpc_vpn module SUMMARY This PR adds transit_gateway_id parameter to ec2_vpc_vpn module. It is needed for the validated content role that manages the creation of transit gateway and attaches VPN to the created transit gateway. ISSUE TYPE Feature Pull Request COMPONENT NAME ADDITIONAL INFORMATION Reviewed-by: Bikouo Aubin Reviewed-by: Alina Buzachis Reviewed-by: GomathiselviS Reviewed-by: Mark Chappell --- .../fragments/transit_gateway_to_vpn.yaml | 3 + plugins/modules/ec2_vpc_vpn.py | 50 ++++++++++++-- .../targets/ec2_vpc_vpn/tasks/main.yml | 65 ++++++++++++++++++- 3 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/transit_gateway_to_vpn.yaml diff --git a/changelogs/fragments/transit_gateway_to_vpn.yaml b/changelogs/fragments/transit_gateway_to_vpn.yaml new file mode 100644 index 00000000000..fa68ca8fab7 --- /dev/null +++ b/changelogs/fragments/transit_gateway_to_vpn.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: +- ec2_vpc_vpn - add support for connecting VPNs to a transit gateway. (https://github.com/ansible-collections/community.aws/pull/1877). diff --git a/plugins/modules/ec2_vpc_vpn.py b/plugins/modules/ec2_vpc_vpn.py index 0efce4a7470..3e4987d9725 100644 --- a/plugins/modules/ec2_vpc_vpn.py +++ b/plugins/modules/ec2_vpc_vpn.py @@ -35,6 +35,7 @@ vpn_gateway_id: description: - The ID of the virtual private gateway. + - Mutually exclusive with I(transit_gateway_id). type: str vpn_connection_id: description: @@ -46,6 +47,12 @@ default: False type: bool required: false + transit_gateway_id: + description: + - The ID of the transit gateway. + - Mutually exclusive with I(vpn_gateway_id). + type: str + version_added: 6.2.0 tunnel_options: description: - An optional list object containing no more than two dict members, each of which may contain I(TunnelInsideCidr) @@ -139,12 +146,18 @@ # Note: None of these examples set aws_access_key, aws_secret_key, or region. # It is assumed that their matching environment variables are set. -- name: create a VPN connection +- name: create a VPN connection with vpn_gateway_id community.aws.ec2_vpc_vpn: state: present vpn_gateway_id: vgw-XXXXXXXX customer_gateway_id: cgw-XXXXXXXX +- name: Attach a vpn connection to transit gateway + community.aws.ec2_vpc_vpn: + state: present + transit_gateway_id: tgw-XXXXXXXX + customer_gateway_id: cgw-XXXXXXXX + - name: modify VPN connection tags community.aws.ec2_vpc_vpn: state: present @@ -231,6 +244,12 @@ returned: I(state=present) sample: vpn_gateway_id: vgw-cb0ae2a2 +transit_gateway_id: + description: The transit gateway id to which the vpn connection can be attached. + type: str + returned: I(state=present) + sample: + transit_gateway_id: tgw-cb0ae2a2 options: description: The VPN connection options (currently only containing static_routes_only). type: complex @@ -421,6 +440,7 @@ def create_filter(module_params, provided_filters): param_to_filter = { "customer_gateway_id": "customer-gateway-id", "vpn_gateway_id": "vpn-gateway-id", + "transit_gateway_id": "transit-gateway-id", "vpn_connection_id": "vpn-connection-id", } @@ -505,6 +525,7 @@ def create_connection( customer_gateway_id, static_only, vpn_gateway_id, + transit_gateway_id, connection_type, max_attempts, delay, @@ -524,17 +545,21 @@ def create_connection( if t_opt: options["TunnelOptions"] = t_opt - if not (customer_gateway_id and vpn_gateway_id): + if not (customer_gateway_id and (vpn_gateway_id or transit_gateway_id)): raise VPNConnectionException( msg=( "No matching connection was found. To create a new connection you must provide " - "both vpn_gateway_id and customer_gateway_id." + "customer_gateway_id and one of either transit_gateway_id or vpn_gateway_id." ) ) + vpn_connection_params = {"Type": connection_type, "CustomerGatewayId": customer_gateway_id, "Options": options} + if vpn_gateway_id: + vpn_connection_params["VpnGatewayId"] = vpn_gateway_id + if transit_gateway_id: + vpn_connection_params["TransitGatewayId"] = transit_gateway_id + try: - vpn = connection.create_vpn_connection( - Type=connection_type, CustomerGatewayId=customer_gateway_id, VpnGatewayId=vpn_gateway_id, Options=options - ) + vpn = connection.create_vpn_connection(**vpn_connection_params) connection.get_waiter("vpn_connection_available").wait( VpnConnectionIds=[vpn["VpnConnection"]["VpnConnectionId"]], WaiterConfig={"Delay": delay, "MaxAttempts": max_attempts}, @@ -674,6 +699,7 @@ def get_check_mode_results(connection, module_params, vpn_connection_id=None, cu "customer_gateway_configuration": "", "customer_gateway_id": module_params.get("customer_gateway_id"), "vpn_gateway_id": module_params.get("vpn_gateway_id"), + "transit_gateway_id": module_params.get("transit_gateway_id"), "options": {"static_routes_only": module_params.get("static_only")}, "routes": [module_params.get("routes")], } @@ -752,6 +778,7 @@ def ensure_present(connection, module_params, check_mode=False): customer_gateway_id=module_params.get("customer_gateway_id"), static_only=module_params.get("static_only"), vpn_gateway_id=module_params.get("vpn_gateway_id"), + transit_gateway_id=module_params.get("transit_gateway_id"), connection_type=module_params.get("connection_type"), tunnel_options=module_params.get("tunnel_options"), max_attempts=max_attempts, @@ -797,6 +824,7 @@ def main(): vpn_gateway_id=dict(type="str"), tags=dict(type="dict", aliases=["resource_tags"]), connection_type=dict(default="ipsec.1", type="str"), + transit_gateway_id=dict(type="str"), tunnel_options=dict(no_log=True, type="list", default=[], elements="dict"), static_only=dict(default=False, type="bool"), customer_gateway_id=dict(type="str"), @@ -807,7 +835,15 @@ def main(): wait_timeout=dict(type="int", default=600), delay=dict(type="int", default=15), ) - module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) + mutually_exclusive = [ + ["vpn_gateway_id", "transit_gateway_id"], + ] + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) connection = module.client("ec2", retry_decorator=VPNRetry.jittered_backoff(retries=10)) state = module.params.get("state") diff --git a/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml b/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml index a4c740887e8..cf33bf9e684 100644 --- a/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml @@ -35,7 +35,63 @@ name: testcgw register: cgw - - name: create vpn connection, with customer gateway + - name: create transit gateway + ec2_transit_gateway: + description: "Transit Gateway for vpn attachment" + register: tgw + + - name: create vpn connection, with customer gateway, vpn_gateway_id and transit_gateway + ec2_vpc_vpn: + customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}' + vpn_gateway_id: '{{ vgw.vgw.id }}' + transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}' + state: present + register: result + ignore_errors: true + + - name: assert creation of vpn failed + assert: + that: + - result is failed + - result.msg == "parameters are mutually exclusive: vpn_gateway_id|transit_gateway_id" + + + - name: create vpn connection, with customer gateway and transit_gateway + ec2_vpc_vpn: + customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}' + transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}' + state: present + register: tgw_vpn + + - name: Store ID of VPN + set_fact: + vpn_id: '{{ tgw_vpn.vpn_connection_id }}' + + # ============================================================ + - name: test success with no parameters + ec2_vpc_vpn_info: + register: result + + - name: assert success with no parameters + assert: + that: + - 'result.changed == false' + - 'result.vpn_connections != []' + # ============================================================ + + - name: Delete vpn created with transit gateway + ec2_vpc_vpn: + state: absent + vpn_connection_id: '{{ vpn_id }}' + register: result + retries: 10 + delay: 3 + until: result is not failed + ignore_errors: true + + # ============================================================ + + - name: create vpn connection, with customer gateway and vpn gateway ec2_vpc_vpn: customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}' vpn_gateway_id: '{{ vgw.vgw.id }}' @@ -47,6 +103,7 @@ vpn_id: '{{ vpn.vpn_connection_id }}' # ============================================================ + - name: test success with no parameters ec2_vpc_vpn_info: register: result @@ -163,3 +220,9 @@ delay: 3 until: result is not failed ignore_errors: true + + - name: delete transit gateway + ec2_transit_gateway: + transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}' + state: absent + ignore_errors: true From 3cf26ab856cd41a034d050a306ef073f3e14215d Mon Sep 17 00:00:00 2001 From: abikouo Date: Mon, 17 Jul 2023 08:53:25 +0200 Subject: [PATCH 2/2] fix: GHA sanity and units tests jobs --- .github/workflows/sanity.yml | 4 ++++ .github/workflows/units.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/sanity.yml b/.github/workflows/sanity.yml index a98c3f47464..24b6d594baa 100644 --- a/.github/workflows/sanity.yml +++ b/.github/workflows/sanity.yml @@ -60,6 +60,10 @@ jobs: { "ansible-version": "devel", "python-version": "3.8" + }, + { + "ansible-version": "devel", + "python-version": "3.9" } ] collection_pre_install: '-r source/tests/sanity/requirements.yml' diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index d389348a5d8..59e3e20c085 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -59,6 +59,10 @@ jobs: { "ansible-version": "devel", "python-version": "3.8" + }, + { + "ansible-version": "devel", + "python-version": "3.9" } ] collection_pre_install: '-r source/tests/unit/requirements.yml'