From e44a947eedfb4155ce3a25085099773108ddc3a8 Mon Sep 17 00:00:00 2001 From: abikouo Date: Fri, 27 Sep 2024 14:37:32 +0200 Subject: [PATCH] add new module ec2_vpc_egress_info --- meta/runtime.yml | 1 + plugins/modules/ec2_vpc_egress_igw_info.py | 139 ++++++++++ .../targets/ec2_vpc_egress_igw/aliases | 2 + .../targets/ec2_vpc_egress_igw/tasks/main.yml | 237 ++++++++++++++++++ 4 files changed, 379 insertions(+) create mode 100644 plugins/modules/ec2_vpc_egress_igw_info.py create mode 100644 tests/integration/targets/ec2_vpc_egress_igw/aliases create mode 100644 tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml diff --git a/meta/runtime.yml b/meta/runtime.yml index 94614615f1e..3f60d9fcff6 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -55,6 +55,7 @@ action_groups: - ec2_vol_info - ec2_vpc_dhcp_option - ec2_vpc_dhcp_option_info + - ec2_vpc_egress_igw_info - ec2_vpc_endpoint - ec2_vpc_endpoint_info - ec2_vpc_endpoint_service_info diff --git a/plugins/modules/ec2_vpc_egress_igw_info.py b/plugins/modules/ec2_vpc_egress_igw_info.py new file mode 100644 index 00000000000..df066a7e245 --- /dev/null +++ b/plugins/modules/ec2_vpc_egress_igw_info.py @@ -0,0 +1,139 @@ +#!/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_egress_igw_info +version_added: 9.0.0 +short_description: Gather information about AWS VPC Egress Only Internet gateway +description: + - Gather information about AWS VPC Egress Only Internet gateway. +author: "Aubin Bikouo (@abikouo)" +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_DescribeEgressOnlyInternetGateways.html) for possible filters. + type: dict + default: {} + egress_only_internet_gateway_ids: + description: + - Get details of specific VPC Egress Internet Gateway ID. + type: list + elements: str +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 VPC Egress only Internet Gateways for an account or profile + amazon.aws.ec2_vpc_igw_info: + region: ap-southeast-2 + profile: production + +- name: Gather information about a filtered list of VPC Egress only Internet Gateways + amazon.aws.ec2_vpc_igw_info: + region: ap-southeast-2 + profile: production + filters: + "tag:Name": "igw-123" + +- name: Gather information about a specific VPC egress only internet gateway by EgressOnlyInternetGatewayId + amazon.aws.ec2_vpc_igw_info: + region: ap-southeast-2 + profile: production + egress_only_internet_gateway_ids: igw-c1231234 +""" + +RETURN = r""" +egress_only_internet_gateways: + description: The AWS Egress only internet gateways. + returned: always + type: list + contains: + attachments: + description: Information about the attachment of the egress-only internet gateway. + returned: always + type: list + contains: + state: + description: The current state of the attachment. + returned: always + type: str + sample: "available" + vpc_id: + description: The ID of the VPC. + returned: always + type: str + sample: "vpc-02123b67" + egress_only_internet_gateway_id: + description: The ID of the egress-only internet gateway. + returned: always + type: str + sample: "eigw-0123456789abcdef" + tags: + description: Any tags assigned to the egress-only internet gateway. + returned: always + type: dict +""" + +from typing import Any +from typing import Dict +from typing import List + +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_egress_only_internet_gateways +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +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 + + +def format_egress_only_internet_gateway(internet_gateway: Dict[str, Any]) -> Dict[str, Any]: + tags = boto3_tag_list_to_ansible_dict(internet_gateway.get("Tags", [])) + egress_only_igw = { + "EgressOnlyInternetGatewayId": internet_gateway["EgressOnlyInternetGatewayId"], + "Attachments": internet_gateway["Attachments"], + "Tags": tags, + } + return camel_dict_to_snake_dict(egress_only_igw, ignore_list=["Tags"]) + + +def list_egress_only_internet_gateways(connection, module: AnsibleAWSModule) -> List[Dict[str, Any]]: + params = dict() + + params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters")) + + if module.params.get("egress_only_internet_gateway_ids"): + params["EgressOnlyInternetGatewayIds"] = module.params.get("egress_only_internet_gateway_ids") + + try: + egress_only_igws = describe_egress_only_internet_gateways(connection, **params) + return [format_egress_only_internet_gateway(igw) for igw in egress_only_igws] + except AnsibleEC2Error as e: + module.fail_json_aws(e, "Unable to describe egress only internet gateways") + + +def main() -> None: + argument_spec = dict( + filters=dict(type="dict", default=dict()), + egress_only_internet_gateway_ids=dict(type="list", elements="str"), + ) + + module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) + client = module.client("ec2") + + results = list_egress_only_internet_gateways(client, module) + module.exit_json(egress_only_internet_gateways=results) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ec2_vpc_egress_igw/aliases b/tests/integration/targets/ec2_vpc_egress_igw/aliases new file mode 100644 index 00000000000..9fd7b5e6ca8 --- /dev/null +++ b/tests/integration/targets/ec2_vpc_egress_igw/aliases @@ -0,0 +1,2 @@ +cloud/aws +ec2_vpc_egress_igw_info diff --git a/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml b/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml new file mode 100644 index 00000000000..d4d27feac3d --- /dev/null +++ b/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml @@ -0,0 +1,237 @@ +--- +- name: Run ec2_vpc_egress_igw integration tests + 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: Test failure with no parameters + community.aws.ec2_vpc_egress_igw: + register: result + ignore_errors: true + + - name: Assert failure with no parameters + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: vpc_id"' + + # ============================================================ + - name: Test failure with non-existent VPC ID + community.aws.ec2_vpc_egress_igw: + state: present + vpc_id: vpc-02394e50abc1807e8 + register: result + ignore_errors: true + + - name: Assert failure with non-existent VPC ID + assert: + that: + - result is failed + - e_msg in result.exception + vars: + e_msg: "The vpc ID 'vpc-02394e50abc1807e8' does not exist" + + # ============================================================ + - name: Create a VPC + amazon.aws.ec2_vpc_net: + name: "{{ resource_prefix }}-vpc" + state: present + cidr_block: "10.232.232.128/26" + tags: + Name: "{{ resource_prefix }}-vpc" + Description: "Created by ansible-test" + register: vpc_result + + # ============================================================ + - name: Create egress-only internet gateway using check_mode=true + community.aws.ec2_vpc_egress_igw: + state: present + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_create_check_mode + check_mode: true + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert module returned changed and the Egress IGW was not created + assert: + that: + - vpc_eigw_create_check_mode is changed + - egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list == [] + + # # ============================================================ + - name: Create egress-only internet gateway (expected changed=true) + community.aws.ec2_vpc_egress_igw: + state: present + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_create + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert module returned changed and the Egress IGW was not created + ansible.builtin.assert: + that: + - vpc_eigw_create is changed + - egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | length == 1 + + # # ============================================================ + - name: Create egress-only internet gateway once again (idempotency) + community.aws.ec2_vpc_egress_igw: + state: present + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_create_idempotency + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert module returned changed and the Egress IGW was not created + ansible.builtin.assert: + that: + - vpc_eigw_create_idempotency is not changed + - vpc_eigw_create_idempotency.gateway_id == vpc_eigw_create.gateway_id + - egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | length == 1 + + # # ============================================================ + - name: Delete egress-only internet gateway (check_mode) + community.aws.ec2_vpc_egress_igw: + state: absent + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_delete_check_mode + check_mode: true + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert module returned changed and the Egress IGW was not created + ansible.builtin.assert: + that: + - vpc_eigw_delete_check_mode is changed + - vpc_eigw_create_idempotency.gateway_id == vpc_eigw_delete_check_mode.gateway_id + - egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | length == 1 + + # # ============================================================ + - name: Delete egress-only internet gateway once again (idempotency) + community.aws.ec2_vpc_egress_igw: + state: absent + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_delete + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert module returned changed and the Egress IGW was not created + ansible.builtin.assert: + that: + - vpc_eigw_delete is changed + - vpc_eigw_create_idempotency.gateway_id == vpc_eigw_delete.gateway_id + - egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list == [] + + # # ============================================================ + - name: Delete egress-only internet gateway + community.aws.ec2_vpc_egress_igw: + state: absent + vpc_id: "{{ vpc_result.vpc.id }}" + register: vpc_eigw_delete_idempotency + + - name: Assert module returned changed and the Egress IGW was not created + ansible.builtin.assert: + that: + - vpc_eigw_delete_idempotency is not changed + + ## ============================================================ + ## Tagging + - name: Create Egress only internet gateway with tags + community.aws.ec2_vpc_egress_igw: + vpc_id: "{{ vpc_result.vpc.id }}" + tags: + ResourcePrefix: "{{ resource_prefix }}" + VpcId: "{{ vpc_result.vpc.id }}" + register: create_with_tags + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert that the Egress IGW was created with tags + ansible.builtin.assert: + that: + - create_with_tags is changed + - egress_info.tags == resource_tags + vars: + egress_info: "{{ egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | first }}" + resource_tags: + ResourcePrefix: "{{ resource_prefix }}" + VpcId: "{{ vpc_result.vpc.id }}" + + - name: Trying to update tags (no change) + community.aws.ec2_vpc_egress_igw: + vpc_id: "{{ vpc_result.vpc.id }}" + tags: + ResourcePrefix: "{{ resource_prefix }}" + VpcId: "{{ vpc_result.vpc.id }}" + register: update_tags + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert that the Egress IGW was not updated + ansible.builtin.assert: + that: + - update_tags is not changed + - egress_info.tags == resource_tags + vars: + egress_info: "{{ egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | first }}" + resource_tags: + ResourcePrefix: "{{ resource_prefix }}" + VpcId: "{{ vpc_result.vpc.id }}" + + - name: Add tag to existing tags + community.aws.ec2_vpc_egress_igw: + vpc_id: "{{ vpc_result.vpc.id }}" + tags: + Phase: integration + purge_tags: false + register: add_tag + + - name: List all Egress only internet gateway + amazon.aws.ec2_vpc_egress_igw_info: + register: egress_only_igws + + - name: Assert that the Egress IGW was created with tags + ansible.builtin.assert: + that: + - add_tag is changed + - egress_info.tags == resource_tags + vars: + egress_info: "{{ egress_only_igws.egress_only_internet_gateways | selectattr('attachments.0.vpc_id', 'equalto', vpc_result.vpc.id) | list | first }}" + resource_tags: + ResourcePrefix: "{{ resource_prefix }}" + VpcId: "{{ vpc_result.vpc.id }}" + Phase: integration + + always: + # ============================================================ + - name: Tidy up EIGW + community.aws.ec2_vpc_egress_igw: + state: absent + vpc_id: "{{ vpc_result.vpc.id }}" + ignore_errors: true + + - name: Tidy up VPC + amazon.aws.ec2_vpc_net: + name: "{{ resource_prefix }}-vpc" + state: absent + cidr_block: "10.232.232.128/26" + ignore_errors: true