diff --git a/changelogs/fragments/refactor-ec2_transit_gateway-modules.yml b/changelogs/fragments/refactor-ec2_transit_gateway-modules.yml new file mode 100644 index 00000000000..cfcfe6476e0 --- /dev/null +++ b/changelogs/fragments/refactor-ec2_transit_gateway-modules.yml @@ -0,0 +1,3 @@ +minor_changes: + - ec2_transit_gateway - Refactor module to use shared code from ``amazon.aws.plugins.module_utils.ec2`` and update ``RETURN`` block (https://github.com/ansible-collections/community.aws/pull/2158). + - ec2_transit_gateway_info - Refactor module to use shared code from ``amazon.aws.plugins.module_utils.ec2`` and update ``RETURN`` block (https://github.com/ansible-collections/community.aws/pull/2158). diff --git a/plugins/modules/ec2_transit_gateway.py b/plugins/modules/ec2_transit_gateway.py index c3a1079e5c9..160d37f4bd6 100644 --- a/plugins/modules/ec2_transit_gateway.py +++ b/plugins/modules/ec2_transit_gateway.py @@ -24,53 +24,44 @@ default: true type: bool auto_attach: - description: - - Enable or disable automatic acceptance of attachment requests. + description: Enable or disable automatic acceptance of attachment requests. default: false type: bool auto_propagate: - description: - - Enable or disable automatic propagation of routes to the default propagation route table. + description: Enable or disable automatic propagation of routes to the default propagation route table. default: true type: bool description: - description: - - The description of the transit gateway. + description: The description of the transit gateway. type: str dns_support: - description: - - Whether to enable AWS DNS support. + description: Whether to enable AWS DNS support. default: true type: bool multicast_support: - description: - - Whether to enable AWS Multicast support. Valid only at the time of creation of the Transit Gateway. + description: Whether to enable AWS Multicast support. Valid only at the time of creation of the Transit Gateway. type: bool version_added: 8.1.0 state: description: - - C(present) to ensure resource is created. - - C(absent) to remove resource. + - V(present) to ensure resource is created. + - V(absent) to remove resource. default: present choices: [ "present", "absent"] type: str transit_gateway_id: - description: - - The ID of the transit gateway. + description: The ID of the transit gateway. type: str vpn_ecmp_support: - description: - - Enable or disable Equal Cost Multipath Protocol support. + description: Enable or disable Equal Cost Multipath Protocol support. default: true type: bool wait: - description: - - Whether to wait for status + description: Whether to wait for status. default: true type: bool wait_timeout: - description: - - number of seconds to wait for status + description: Number of seconds to wait for status. default: 300 type: int @@ -123,7 +114,7 @@ RETURN = r""" transit_gateway: description: The attributes of the transit gateway. - type: complex + type: dict returned: I(state=present) contains: creation_time: @@ -135,11 +126,11 @@ description: The description of the transit gateway. returned: always type: str - sample: my test tgw + sample: "my test tgw" options: - description: The options attributes of the transit gateway + description: The options attributes of the transit gateway. returned: always - type: complex + type: dict contains: amazon_side_asn: description: @@ -147,64 +138,64 @@ The range is 64512 to 65534 for 16-bit ASNs and 4200000000 to 4294967294 for 32-bit ASNs. returned: always type: str - sample: 64512 + sample: "64512" auto_accept_shared_attachements: description: Indicates whether attachment requests are automatically accepted. returned: always type: str - sample: disable + sample: "disable" default_route_table_association: description: - Indicates whether resource attachments are automatically associated with the default association route table. returned: always type: str - sample: enable + sample: "enable" association_default_route_table_id: description: The ID of the default association route table. returned: Iwhen exists type: str - sample: tgw-rtb-abc123444 + sample: "tgw-rtb-abc123444" default_route_table_propagation: description: - Indicates whether resource attachments automatically propagate routes to the default propagation route table. returned: always type: str - sample: disable + sample: "disable" propagation_default_route_table_id: description: The ID of the default propagation route table. returned: when exists type: str - sample: tgw-rtb-def456777 + sample: "tgw-rtb-def456777" vpn_ecmp_support: description: Indicates whether Equal Cost Multipath Protocol support is enabled. returned: always type: str - sample: enable + sample: "enable" dns_support: description: Indicates whether DNS support is enabled. returned: always type: str - sample: enable + sample: "enable" multicast_support: description: Indicates whether Multicast support is enabled. returned: always type: str - sample: enable + sample: "enable" version_added: 7.3.0 owner_id: description: The account that owns the transit gateway. returned: always type: str - sample: '123456789012' + sample: "123456789012" state: description: The state of the transit gateway. returned: always type: str - sample: pending + sample: "pending" tags: - description: A dictionary of resource tags + description: A dictionary of resource tags. returned: always type: dict sample: @@ -214,52 +205,44 @@ description: The ID of the transit_gateway. returned: always type: str - sample: tgw-3a9aa123 + sample: "tgw-3a9aa123" transit_gateway_id: description: The ID of the transit_gateway. returned: always type: str - sample: tgw-3a9aa123 + sample: "tgw-3a9aa123" """ -from time import sleep -from time import time - -try: - from botocore.exceptions import BotoCoreError - from botocore.exceptions import ClientError -except ImportError: - pass # handled by imported AnsibleAWSModule +from typing import Any +from typing import Dict +from typing import Optional from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import create_ec2_transit_gateway +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import delete_ec2_transit_gateway +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_ec2_transit_gateways 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.transformation import ansible_dict_to_boto3_filter_list +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 -class AnsibleEc2Tgw(object): - def __init__(self, module, results): +class AnsibleEc2Tgw: + def __init__(self, module: AnsibleAWSModule, results: Dict[str, Any]) -> None: self._module = module self._results = results retry_decorator = AWSRetry.jittered_backoff( catch_extra_error_codes=["IncorrectState"], ) - connection = module.client("ec2", retry_decorator=retry_decorator) - self._connection = connection + self._connection = module.client("ec2") self._check_mode = self._module.check_mode - def process(self): - """Process the request based on state parameter . - state = present will search for an existing tgw based and return the object data. - if no object is found it will be created - - state = absent will attempt to remove the tgw however will fail if it still has - attachments or associations - """ + def process(self) -> None: + """Process the request based on state parameter.""" description = self._module.params.get("description") state = self._module.params.get("state", "present") tgw_id = self._module.params.get("transit_gateway_id") @@ -269,71 +252,60 @@ def process(self): elif state == "absent": self.ensure_tgw_absent(tgw_id, description) - def wait_for_status(self, wait_timeout, tgw_id, status, skip_deleted=True): + def wait_for_status(self, wait_timeout: int, tgw_id: str, status: str, skip_deleted: bool = True) -> Dict[str, Any]: """ - Wait for the Transit Gateway to reach the specified status + Wait for the Transit Gateway to reach the specified status. :param wait_timeout: Number of seconds to wait, until this timeout is reached. - :param tgw_id: The Amazon nat id. + :param tgw_id: The Amazon NAT ID. :param status: The status to wait for. - examples. status=available, status=deleted - :param skip_deleted: ignore deleted transit gateways - :return dict: transit gateway object + :param skip_deleted: Ignore deleted transit gateways. + :return: Transit gateway object. """ polling_increment_secs = 5 - wait_timeout = time() + wait_timeout - status_achieved = False - transit_gateway = dict() - - while wait_timeout > time(): - try: - transit_gateway = self.get_matching_tgw(tgw_id=tgw_id, skip_deleted=skip_deleted) - - if transit_gateway: - if self._check_mode: - transit_gateway["state"] = status - - if transit_gateway.get("state") == status: - status_achieved = True - break + max_attempts = wait_timeout // polling_increment_secs - elif transit_gateway.get("state") == "failed": - break + waiter_method = f"transit_gateway_{status}" - else: - sleep(polling_increment_secs) - - except ClientError as e: - self._module.fail_json_aws(e) + wait_for_resource_state( + self._connection, + self._module, + waiter_method, + TransitGatewayIds=[tgw_id], + delay=polling_increment_secs, + max_attempts=max_attempts, + ) - if not status_achieved: - self._module.fail_json(msg="Wait time out reached, while waiting for results") + transit_gateway = self.get_matching_tgw(tgw_id=tgw_id, skip_deleted=skip_deleted) + if transit_gateway is None: + self._module.fail_json(msg="Transit Gateway not found after waiting.") return transit_gateway - def get_matching_tgw(self, tgw_id, description=None, skip_deleted=True): - """search for an existing tgw by either tgw_id or description - :param tgw_id: The AWS id of the transit gateway - :param description: The description of the transit gateway. - :param skip_deleted: ignore deleted transit gateways - :return dict: transit gateway object + def get_matching_tgw( + self, tgw_id: Optional[str], description: Optional[str] = None, skip_deleted: bool = True + ) -> Optional[Dict[str, Any]]: + """Search for an existing tgw by either tgw_id or description. + :param tgw_id: The AWS id of the transit gateway. + :param description: The description of the transit gateway. + :param skip_deleted: Ignore deleted transit gateways. + :return: Transit gateway object. """ filters = [] + params = {} if tgw_id: filters = ansible_dict_to_boto3_filter_list({"transit-gateway-id": tgw_id}) - try: - response = AWSRetry.exponential_backoff()(self._connection.describe_transit_gateways)(Filters=filters) - except (ClientError, BotoCoreError) as e: - self._module.fail_json_aws(e) + params["Filters"] = filters + response = describe_ec2_transit_gateways(self._connection, **params) tgw = None tgws = [] - if len(response.get("TransitGateways", [])) == 1 and tgw_id: - if (response["TransitGateways"][0]["State"] != "deleted") or not skip_deleted: - tgws.extend(response["TransitGateways"]) + if len(response) == 1 and tgw_id: + if (response[0]["State"] != "deleted") or not skip_deleted: + tgws.extend(response) - for gateway in response.get("TransitGateways", []): + for gateway in response: if description == gateway["Description"] and gateway["State"] != "deleted": tgws.append(gateway) @@ -348,21 +320,18 @@ def get_matching_tgw(self, tgw_id, description=None, skip_deleted=True): return tgw @staticmethod - def enable_option_flag(flag): + def enable_option_flag(flag: Optional[bool]) -> str: disabled = "disable" enabled = "enable" - if flag: - return enabled - return disabled + return enabled if flag else disabled - def create_tgw(self, description): + def create_tgw(self, description: str) -> Dict[str, Any]: """ Create a transit gateway and optionally wait for status to become available. - :param description: The description of the transit gateway. - :return dict: transit gateway object + :return: Transit gateway object. """ - options = dict() + options: Dict[str, Any] = {} wait = self._module.params.get("wait") wait_timeout = self._module.params.get("wait_timeout") @@ -376,36 +345,31 @@ def create_tgw(self, description): options["DnsSupport"] = self.enable_option_flag(self._module.params.get("dns_support")) options["MulticastSupport"] = self.enable_option_flag(self._module.params.get("multicast_support")) - try: - response = self._connection.create_transit_gateway(Description=description, Options=options) - except (ClientError, BotoCoreError) as e: - self._module.fail_json_aws(e) + params = {"Description": description, "Options": options} - tgw_id = response["TransitGateway"]["TransitGatewayId"] + response = create_ec2_transit_gateway(self._connection, **params) + + tgw_id = response["TransitGatewayId"] if wait: result = self.wait_for_status(wait_timeout=wait_timeout, tgw_id=tgw_id, status="available") else: result = self.get_matching_tgw(tgw_id=tgw_id) - self._results["msg"] = f" Transit gateway {result['transit_gateway_id']} created" + self._results["msg"] = f"Transit gateway {result['transit_gateway_id']} created" return result - def delete_tgw(self, tgw_id): + def delete_tgw(self, tgw_id: str) -> Dict[str, Any]: """ - De;lete the transit gateway and optionally wait for status to become deleted - - :param tgw_id: The id of the transit gateway - :return dict: transit gateway object + Delete the transit gateway and optionally wait for status to become deleted. + :param tgw_id: The id of the transit gateway. + :return: Transit gateway object. """ wait = self._module.params.get("wait") wait_timeout = self._module.params.get("wait_timeout") - try: - response = self._connection.delete_transit_gateway(TransitGatewayId=tgw_id) - except (ClientError, BotoCoreError) as e: - self._module.fail_json_aws(e) + delete_ec2_transit_gateway(self._connection, tgw_id) if wait: result = self.wait_for_status( @@ -414,18 +378,17 @@ def delete_tgw(self, tgw_id): else: result = self.get_matching_tgw(tgw_id=tgw_id, skip_deleted=False) - self._results["msg"] = f" Transit gateway {tgw_id} deleted" + self._results["msg"] = f"Transit gateway {tgw_id} deleted" return result - def ensure_tgw_present(self, tgw_id=None, description=None): + def ensure_tgw_present(self, tgw_id: Optional[str] = None, description: Optional[str] = None) -> Dict[str, Any]: """ - Will create a tgw if no match to the tgw_id or description are found - Will update the tgw tags if matching one found but tags are not synced - - :param tgw_id: The AWS id of the transit gateway - :param description: The description of the transit gateway. - :return dict: transit gateway object + Will create a tgw if no match to the tgw_id or description are found. + Will update the tgw tags if matching one found but tags are not synced. + :param tgw_id: The AWS id of the transit gateway. + :param description: The description of the transit gateway. + :return: Transit gateway object. """ tgw = self.get_matching_tgw(tgw_id, description) @@ -435,13 +398,10 @@ def ensure_tgw_present(self, tgw_id=None, description=None): self._results["transit_gateway_id"] = None return self._results - try: - if not description: - self._module.fail_json(msg="Failed to create Transit Gateway: description argument required") - tgw = self.create_tgw(description) - self._results["changed"] = True - except (BotoCoreError, ClientError) as e: - self._module.fail_json_aws(e, msg="Unable to create Transit Gateway") + if not description: + self._module.fail_json(msg="Failed to create Transit Gateway: description argument required") + tgw = self.create_tgw(description) + self._results["changed"] = True self._results["changed"] |= ensure_ec2_tags( self._connection, @@ -455,13 +415,12 @@ def ensure_tgw_present(self, tgw_id=None, description=None): return self._results - def ensure_tgw_absent(self, tgw_id=None, description=None): + def ensure_tgw_absent(self, tgw_id: Optional[str] = None, description: Optional[str] = None) -> Dict[str, Any]: """ - Will delete the tgw if a single tgw is found not yet in deleted status - - :param tgw_id: The AWS id of the transit gateway - :param description: The description of the transit gateway. - :return doct: transit gateway object + Will delete the tgw if a single tgw is found not yet in deleted status. + :param tgw_id: The AWS id of the transit gateway. + :param description: The description of the transit gateway. + :return: Transit gateway object. """ self._results["transit_gateway_id"] = None tgw = self.get_matching_tgw(tgw_id, description) @@ -471,19 +430,16 @@ def ensure_tgw_absent(self, tgw_id=None, description=None): self._results["changed"] = True return self._results - try: - tgw = self.delete_tgw(tgw_id=tgw["transit_gateway_id"]) - self._results["changed"] = True - self._results["transit_gateway"] = self.get_matching_tgw( - tgw_id=tgw["transit_gateway_id"], skip_deleted=False - ) - except (BotoCoreError, ClientError) as e: - self._module.fail_json_aws(e, msg="Unable to delete Transit Gateway") + tgw = self.delete_tgw(tgw_id=tgw["transit_gateway_id"]) + self._results["changed"] = True + self._results["transit_gateway"] = self.get_matching_tgw( + tgw_id=tgw["transit_gateway_id"], skip_deleted=False + ) return self._results -def setup_module_object(): +def setup_module_object() -> AnsibleAWSModule: """ merge argument spec and create Ansible module object :return: Ansible module object diff --git a/plugins/modules/ec2_transit_gateway_info.py b/plugins/modules/ec2_transit_gateway_info.py index 014c875b6a0..f07be7ae941 100644 --- a/plugins/modules/ec2_transit_gateway_info.py +++ b/plugins/modules/ec2_transit_gateway_info.py @@ -6,24 +6,25 @@ DOCUMENTATION = r""" module: ec2_transit_gateway_info -short_description: Gather information about ec2 transit gateways in AWS +short_description: Retrieve information about EC2 Transit Gateways in AWS version_added: 1.0.0 description: - - Gather information about ec2 transit gateways in AWS + - Gather information about EC2 Transit Gateways in AWS. author: - "Bob Boldin (@BobBoldin)" options: transit_gateway_ids: description: - - A list of transit gateway IDs to gather information for. + - A list of Transit Gateway IDs for which to gather information. aliases: [transit_gateway_id] type: list elements: str default: [] 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_DescribeTransitGateways.html) for filters. + - A dictionary of filters to apply to the query. Each key-value pair represents a filter key and its corresponding value. + - For a complete list of available filters, + refer to the AWS documentation U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeTransitGateways.html). type: dict default: {} extends_documentation_fragment: @@ -58,11 +59,12 @@ RETURN = r""" transit_gateways: - description: > - Transit gateways that match the provided filters. Each element consists of a dict with all the information - related to that transit gateway. + description: + - Transit gateways that match the provided filters. + - Each element consists of a dict with all the information related to that transit gateway. returned: on success - type: complex + type: list + elements: dict contains: creation_time: description: The creation time. @@ -77,65 +79,53 @@ options: description: A dictionary of the transit gateway options. returned: always - type: complex + type: dict contains: amazon_side_asn: description: - - A private Autonomous System Number (ASN) for the Amazon - side of a BGP session. The range is 64512 to 65534 for - 16-bit ASNs and 4200000000 to 4294967294 for 32-bit ASNs. + - A private Autonomous System Number (ASN) for the Amazon ide of a BGP session. + - The range is 64512 to 65534 for 16-bit ASNs and 4200000000 to 4294967294 for 32-bit ASNs. returned: always type: int sample: 64512 auto_accept_shared_attachments: - description: - - Indicates whether attachment requests are automatically accepted. + description: Indicates whether attachment requests are automatically accepted. returned: always type: str sample: "enable" default_route_table_association: - description: - - Indicates whether resource attachments are automatically - associated with the default association route table. + description: Indicates whether resource attachments are automatically associated with the default association route table. returned: always type: str sample: "disable" association_default_route_table_id: - description: - - The ID of the default association route table. + description: The ID of the default association route table. returned: when present type: str - sample: "rtb-11223344" + sample: "tgw-rtb-0fd332c911223344" default_route_table_propagation: - description: - - Indicates whether resource attachments automatically - propagate routes to the default propagation route table. + description: Indicates whether resource attachments automatically propagate routes to the default propagation route table. returned: always type: str sample: "disable" dns_support: - description: - - Indicates whether DNS support is enabled. + description: Indicates whether DNS support is enabled. returned: always type: str sample: "enable" multicast_support: - description: - - Indicates whether Multicast support is enabled. + description: Indicates whether Multicast support is enabled. returned: always type: str sample: "enable" version_added: 7.3.0 propagation_default_route_table_id: - description: - - The ID of the default propagation route table. + description: The ID of the default propagation route table. returned: when present type: str sample: "rtb-11223344" vpn_ecmp_support: - description: - - Indicates whether Equal Cost Multipath Protocol support - is enabled. + description: Indicates whether Equal Cost Multipath Protocol support is enabled. returned: always type: str sample: "enable" @@ -153,9 +143,10 @@ description: A dict of tags associated with the transit gateway. returned: always type: dict - sample: '{ - "Name": "A sample TGW" - }' + sample: { + "Name": "A sample TGW", + "Env": "Dev" + } transit_gateway_arn: description: The Amazon Resource Name (ARN) of the transit gateway. returned: always @@ -168,67 +159,70 @@ sample: "tgw-02c42332e6b7da829" """ -try: - import botocore -except ImportError: - pass # handled by imported AnsibleAWSModule +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.botocore import is_boto3_error_code -from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleEC2Error +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_ec2_transit_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 -class AnsibleEc2TgwInfo(object): - def __init__(self, module, results): - self._module = module - self._results = results - self._connection = self._module.client("ec2") - self._check_mode = self._module.check_mode +def get_transit_gateway_response(module: AnsibleAWSModule, connection) -> Dict[str, Any]: + """ + Get transit gateway response from AWS. - @AWSRetry.exponential_backoff() - def describe_transit_gateways(self): - """ - Describe transit gateways. + module : AnsibleAWSModule object + connection : boto3 client connection object + :return: Response from describe_transit_gateways call + """ + filters = ansible_dict_to_boto3_filter_list(module.params["filters"]) + transit_gateway_ids = module.params["transit_gateway_ids"] - module : AnsibleAWSModule object - connection : boto3 client connection object - """ - # collect parameters - filters = ansible_dict_to_boto3_filter_list(self._module.params["filters"]) - transit_gateway_ids = self._module.params["transit_gateway_ids"] + params = {} + if transit_gateway_ids: + params["TransitGatewayIds"] = transit_gateway_ids + if filters: + params["Filters"] = filters - # init empty list for return vars - transit_gateway_info = list() + result = describe_ec2_transit_gateways(connection, **params) + return result - # Get the basic transit gateway info - try: - response = self._connection.describe_transit_gateways( - TransitGatewayIds=transit_gateway_ids, Filters=filters - ) - except is_boto3_error_code("InvalidTransitGatewayID.NotFound"): - self._results["transit_gateways"] = [] - return - for transit_gateway in response["TransitGateways"]: - transit_gateway_info.append(camel_dict_to_snake_dict(transit_gateway, ignore_list=["Tags"])) - # convert tag list to ansible dict - transit_gateway_info[-1]["tags"] = boto3_tag_list_to_ansible_dict(transit_gateway.get("Tags", [])) +def extract_transit_gateway_info(transit_gateway: Dict[str, Any]) -> Dict[str, Any]: + """ + Extract and transform transit gateway information. - self._results["transit_gateways"] = transit_gateway_info - return + transit_gateway : The transit gateway data from AWS + :return: Transformed transit gateway information + """ + tgw_data = camel_dict_to_snake_dict(transit_gateway, ignore_list=["Tags"]) + tgw_data["tags"] = boto3_tag_list_to_ansible_dict(transit_gateway.get("Tags", [])) + return tgw_data -def setup_module_object(): +def describe_transit_gateways(module: AnsibleAWSModule, connection) -> List[Dict[str, Any]]: """ - merge argument spec and create Ansible module object - :return: Ansible module object + Describe transit gateways. + + module : AnsibleAWSModule object + connection : boto3 client connection object + :return: List of transit gateways """ + response = get_transit_gateway_response(module, connection) + return [extract_transit_gateway_info(tgw) for tgw in response] + +def setup_module_object() -> AnsibleAWSModule: + """ + Merge argument spec and create Ansible module object. + :return: Ansible module object + """ argument_spec = dict( transit_gateway_ids=dict(type="list", default=[], elements="str", aliases=["transit_gateway_id"]), filters=dict(type="dict", default={}), @@ -244,13 +238,13 @@ def setup_module_object(): def main(): module = setup_module_object() + results = {"changed": False} - results = dict(changed=False) - - tgwf_manager = AnsibleEc2TgwInfo(module=module, results=results) + connection = module.client("ec2") try: - tgwf_manager.describe_transit_gateways() - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + transit_gateways = describe_transit_gateways(module, connection) + results["transit_gateways"] = transit_gateways + except AnsibleEC2Error as e: module.fail_json_aws(e) module.exit_json(**results) diff --git a/tests/integration/targets/ec2_transit_gateway/tasks/main.yml b/tests/integration/targets/ec2_transit_gateway/tasks/main.yml index 241c9c2c324..fe542b1e1ec 100644 --- a/tests/integration/targets/ec2_transit_gateway/tasks/main.yml +++ b/tests/integration/targets/ec2_transit_gateway/tasks/main.yml @@ -1,5 +1,5 @@ --- -- name: 'ec2_transit_gateway integration tests' +- name: Run 'ec2_transit_gateway integration tests' collections: - amazon.aws module_defaults: @@ -10,159 +10,291 @@ region: '{{ aws_region }}' block: - - name: generate unique value for testing - set_fact: + - name: Generate unique value for testing + ansible.builtin.set_fact: tgw_description: "{{ resource_prefix }}-tgw" - - name: test create transit gateway without tags - ec2_transit_gateway: + - name: Test create transit gateway without tags - check_mode + community.aws.ec2_transit_gateway: description: "{{ tgw_description }}" register: create_result - - name: assert changed is True - assert: + check_mode: true + + - name: Assert changed is True - check_mode + ansible.builtin.assert: + that: + - create_result.changed == True + - '"ec2:CreateTransitGateway" not in create_result.resource_actions' + + - name: Test create transit gateway without tags + community.aws.ec2_transit_gateway: + description: "{{ tgw_description }}" + register: create_result + + - name: Assert changed is True + ansible.builtin.assert: that: - create_result.changed == True - - - name: test update transit gateway with tags by description - ec2_transit_gateway: + + - name: Test create transit gateway without tags - idempotency + community.aws.ec2_transit_gateway: + description: "{{ tgw_description }}" + register: create_result + + - name: Assert changed is True + ansible.builtin.assert: + that: + - create_result.changed == False + - '"ec2:CreateTransitGateway" not in create_result.resource_actions' + + - name: Test update transit gateway with tags by description - check_mode + community.aws.ec2_transit_gateway: description: "{{ tgw_description }}" tags: Name: Ansible Test TGW register: result - - name: assert changed is True - assert: + check_mode: true + + - name: Assert changed is True - check_mode + ansible.builtin.assert: + that: + - result.changed == True + - '"ec2:CreateTags" not in result.resource_actions' + + - name: Test update transit gateway with tags by description + community.aws.ec2_transit_gateway: + description: "{{ tgw_description }}" + tags: + Name: Ansible Test TGW + register: result + + - name: Assert changed is True + ansible.builtin.assert: that: - result.changed == True - result.transit_gateway.tags | length == 1 - "'Name' in result.transit_gateway.tags" - - name: test update transit gateway with new tag and purge_tags false - ec2_transit_gateway: + - name: Test update transit gateway with tags by description - idempotency + community.aws.ec2_transit_gateway: + description: "{{ tgw_description }}" + tags: + Name: Ansible Test TGW + register: result + + - name: Assert changed is False - idempotency + ansible.builtin.assert: + that: + - result.changed == False + - result.transit_gateway.tags | length == 1 + - "'Name' in result.transit_gateway.tags" + + - name: Test update transit gateway with new tag and purge_tags false - check_mode + community.aws.ec2_transit_gateway: + transit_gateway_id: '{{ create_result.transit_gateway.transit_gateway_id }}' + purge_tags: False + tags: + status: ok to delete + register: result + check_mode: true + + - name: Assert changed is True and have 2 tags - check_mode + ansible.builtin.assert: + that: + - result.changed == True + - result.transit_gateway.tags | length != 2 + - "'Name' in result.transit_gateway.tags" + - '"ec2:CreateTags" not in result.resource_actions' + + - name: Test update transit gateway with new tag and purge_tags false + community.aws.ec2_transit_gateway: transit_gateway_id: '{{ create_result.transit_gateway.transit_gateway_id }}' purge_tags: False tags: status: ok to delete register: result - - name: assert changed is True and have 2 tags - assert: + + - name: Assert changed is True and have 2 tags + ansible.builtin.assert: that: - result.changed == True - result.transit_gateway.tags | length == 2 - "'Name' in result.transit_gateway.tags" - - name: test update transit gateway with purge_tags true - ec2_transit_gateway: + - name: Test update transit gateway with new tag and purge_tags false - idempotency + community.aws.ec2_transit_gateway: + transit_gateway_id: '{{ create_result.transit_gateway.transit_gateway_id }}' + purge_tags: False + tags: + status: ok to delete + register: result + + - name: Assert changed is True and have 2 tags - idempotency + ansible.builtin.assert: + that: + - result.changed == False + - result.transit_gateway.tags | length == 2 + - "'Name' in result.transit_gateway.tags" + + - name: Test update transit gateway with purge_tags true - check_mode + community.aws.ec2_transit_gateway: + transit_gateway_id: '{{ create_result.transit_gateway.transit_gateway_id }}' + purge_tags: True + tags: + status: ok to delete + register: result + check_mode: true + + - name: Assert changed is True and TGW tag is absent - check_mode + ansible.builtin.assert: + that: + - result.changed == True + - result.transit_gateway.tags | length == 2 + - '"ec2:DeleteTags" not in result.resource_actions' + + - name: Test update transit gateway with purge_tags true + community.aws.ec2_transit_gateway: transit_gateway_id: '{{ create_result.transit_gateway.transit_gateway_id }}' purge_tags: True tags: status: ok to delete register: result - - name: assert changed is True and TGW tag is absent - assert: + + - name: Assert changed is True and TGW tag is absent + ansible.builtin.assert: that: - result.changed == True - result.transit_gateway.tags | length == 1 - "'Name' not in result.transit_gateway.tags" - - name: test idempotence - ec2_transit_gateway: + - name: Test idempotence + community.aws.ec2_transit_gateway: description: "{{ tgw_description }}" purge_tags: True tags: status: ok to delete register: result - - name: assert changed is False - assert: + + - name: Assert changed is False + ansible.builtin.assert: that: - result.changed == False - - - name: generate unique value for testing - set_fact: + + - name: Generate unique value for testing + ansible.builtin.set_fact: tgw_description_multicast: "{{ resource_prefix }}-tgw-multicast" - - - name: test create transit gateway with multicast enabled - ec2_transit_gateway: + + - name: Test create transit gateway with multicast enabled - check_mode + community.aws.ec2_transit_gateway: description: "{{ tgw_description_multicast }}" multicast_support: true register: create_result - - - name: assert changed is True - assert: + check_mode: true + + - name: Assert changed is True - check_mode + ansible.builtin.assert: that: - create_result.changed == True - - - name: test success with filter - ec2_transit_gateway_info: + - '"ec2:CreateTransitGateway" not in create_result.resource_actions' + + - name: Test create transit gateway with multicast enabled + community.aws.ec2_transit_gateway: + description: "{{ tgw_description_multicast }}" + multicast_support: true + register: create_result + + - name: Assert changed is True + ansible.builtin.assert: + that: + - create_result.changed == True + + - name: Test create transit gateway with multicast enabled - idempotency + community.aws.ec2_transit_gateway: + description: "{{ tgw_description_multicast }}" + multicast_support: true + register: create_result + + - name: Assert changed is True - idempotency + ansible.builtin.assert: + that: + - create_result.changed == False + + - name: Test success with filter + community.aws.ec2_transit_gateway_info: filters: options.multicast-support: enable register: result - - - name: assert success with multicast-support filter - assert: + + - name: Assert success with multicast-support filter + ansible.builtin.assert: that: - 'result.transit_gateways != []' # ==== Combine ec2_transit_gateway_info ====================== - - name: test success with no parameters - ec2_transit_gateway_info: + - name: Test success with no parameters + community.aws.ec2_transit_gateway_info: register: result - - name: assert success with no parameters - assert: + - name: Assert success with no parameters + ansible.builtin.assert: that: - 'result.changed == false' - 'result.transit_gateways != []' - - name: test success with single filter - ec2_transit_gateway_info: + - name: Test success with single filter + community.aws.ec2_transit_gateway_info: filters: transit-gateway-id: "{{ create_result.transit_gateway.transit_gateway_id }}" register: result - - name: assert success with transit_gateway_id filter - assert: + + - name: Assert success with transit_gateway_id filter + ansible.builtin.assert: that: - 'result.changed == false' - 'result.transit_gateways != []' - - name: test empty result set for non-existent tgw id via filter - ec2_transit_gateway_info: + - name: Test empty result set for non-existent tgw id via filter + community.aws.ec2_transit_gateway_info: filters: transit-gateway-id: tgw-00000011111111122 register: result - - name: assert success with transit_gateway_id filter - assert: + + - name: Assert success with transit_gateway_id filter + ansible.builtin.assert: that: - 'result.changed == false' - 'result.transit_gateways == []' - - name: test NotFound exception caught and returned empty result set - ec2_transit_gateway_info: + - name: Test NotFound exception caught and returned empty result set + community.aws.ec2_transit_gateway_info: transit_gateway_id: tgw-00000011111111122 register: result - - name: assert success with transit_gateway_id filter - assert: + + - name: Assert success with transit_gateway_id filter + ansible.builtin.assert: that: - 'result.changed == false' - 'result.transit_gateways == []' - - name: test success with multiple filters - ec2_transit_gateway_info: + - name: Test success with multiple filters + community.aws.ec2_transit_gateway_info: filters: options.dns-support: enable options.vpn-ecmp-support: enable register: result - - name: assert success with transit_gateway_id filter - assert: + + - name: Assert success with transit_gateway_id filter + ansible.builtin.assert: that: - 'result.changed == false' - 'result.transit_gateways != []' - + always: ###### TEARDOWN STARTS HERE ###### - - name: delete transit gateway - ec2_transit_gateway: + - name: Delete transit gateway + community.aws.ec2_transit_gateway: description: "{{ item }}" state: absent - ignore_errors: yes + ignore_errors: true loop: - "{{ tgw_description }}" - "{{ tgw_description_multicast }}" diff --git a/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/setup.yml b/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/setup.yml index f3b3e86f387..9dddd46c634 100644 --- a/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/setup.yml +++ b/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/setup.yml @@ -8,7 +8,7 @@ subnet_az_b_1: '{{ ec2_availability_zone_names[0] }}' subnet_az_b_2: '{{ ec2_availability_zone_names[1] }}' -- name: Create Transit Gateways +- name: 'Create Transit Gateways' community.aws.ec2_transit_gateway: description: '{{ item.description }}' tags: