From a30fc97009fb8021b7b10400ec324b0873c33221 Mon Sep 17 00:00:00 2001 From: abikouo Date: Wed, 25 Sep 2024 16:03:12 +0200 Subject: [PATCH] Prepare modules ec2_vpc_nacl and ec2_vpc_nacl_info for promotion --- ...0240924-refactor-ec2_vpc_nacl-modules.yaml | 4 + plugins/modules/ec2_vpc_nacl.py | 626 ++++++++---------- plugins/modules/ec2_vpc_nacl_info.py | 100 +-- .../ec2_vpc_nacl/tasks/ingress_and_egress.yml | 36 +- .../targets/ec2_vpc_nacl/tasks/ipv6.yml | 33 +- .../targets/ec2_vpc_nacl/tasks/main.yml | 62 +- .../targets/ec2_vpc_nacl/tasks/subnet_ids.yml | 32 +- .../ec2_vpc_nacl/tasks/subnet_names.yml | 28 +- .../targets/ec2_vpc_nacl/tasks/tags.yml | 113 ++-- 9 files changed, 508 insertions(+), 526 deletions(-) create mode 100644 changelogs/fragments/20240924-refactor-ec2_vpc_nacl-modules.yaml diff --git a/changelogs/fragments/20240924-refactor-ec2_vpc_nacl-modules.yaml b/changelogs/fragments/20240924-refactor-ec2_vpc_nacl-modules.yaml new file mode 100644 index 00000000000..624b71a8dfd --- /dev/null +++ b/changelogs/fragments/20240924-refactor-ec2_vpc_nacl-modules.yaml @@ -0,0 +1,4 @@ +--- +minor_changes: + - ec2_vpc_nacl_info - Refactor module to use shared code from `amazon.aws.plugins.module_utils.ec2` (). + - ec2_vpc_nacl - Refactor module to use shared code from `amazon.aws.plugins.module_utils.ec2` (). \ No newline at end of file diff --git a/plugins/modules/ec2_vpc_nacl.py b/plugins/modules/ec2_vpc_nacl.py index cf109de1c8b..750f06ba00f 100644 --- a/plugins/modules/ec2_vpc_nacl.py +++ b/plugins/modules/ec2_vpc_nacl.py @@ -15,13 +15,15 @@ name: description: - Tagged name identifying a network ACL. - - One and only one of the I(name) or I(nacl_id) is required. + - One and only one of the O(name) or O(nacl_id) is required. + - Mutually exclusive with O(nacl_id). required: false type: str nacl_id: description: - NACL id identifying a network ACL. - - One and only one of the I(name) or I(nacl_id) is required. + - One and only one of the O(name) or O(nacl_id) is required. + - Mutually exclusive with O(name). required: false type: str vpc_id: @@ -142,10 +144,6 @@ """ RETURN = r""" -task: - description: The result of the create, or delete action. - returned: success - type: dict nacl_id: description: The id of the NACL (when creating or updating an ACL) returned: success @@ -153,14 +151,21 @@ sample: acl-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 ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleEC2Error +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import create_network_acl +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import create_network_acl_entry +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import delete_network_acl +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import delete_network_acl_entry +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_network_acls +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_subnets 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_specifications +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import replace_network_acl_association from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule @@ -170,70 +175,63 @@ # Utility methods -def icmp_present(entry): - if len(entry) == 6 and entry[1] in ["icmp", "ipv6-icmp"] or entry[1] in [1, 58]: - return True - - -def subnets_removed(nacl_id, subnets, client, module): - results = find_acl_by_id(nacl_id, client, module) - associations = results["NetworkAcls"][0]["Associations"] - subnet_ids = [assoc["SubnetId"] for assoc in associations] - return [subnet for subnet in subnet_ids if subnet not in subnets] +def icmp_present(entry: List[str]) -> bool: + return len(entry) == 6 and entry[1] in ["icmp", "ipv6-icmp"] or entry[1] in [1, 58] -def subnets_added(nacl_id, subnets, client, module): - results = find_acl_by_id(nacl_id, client, module) - associations = results["NetworkAcls"][0]["Associations"] - subnet_ids = [assoc["SubnetId"] for assoc in associations] - return [subnet for subnet in subnets if subnet not in subnet_ids] - - -def subnets_changed(nacl, client, module): +def subnets_changed(client, module: AnsibleAWSModule, nacl_id: str, subnets_ids: List[str]) -> bool: changed = False vpc_id = module.params.get("vpc_id") - nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"] - subnets = subnets_to_associate(nacl, client, module) - if not subnets: - default_nacl_id = find_default_vpc_nacl(vpc_id, client, module)[0] - subnets = find_subnet_ids_by_nacl_id(nacl_id, client, module) - if subnets: - replace_network_acl_association(default_nacl_id, subnets, client, module) - changed = True - return changed - changed = False + + if not subnets_ids: + default_nacl_id = find_default_vpc_nacl(client, module, vpc_id) + # Find subnets by Network ACL ids + network_acls = describe_network_acls( + client, Filters=[{"Name": "association.network-acl-id", "Values": [nacl_id]}] + ) + subnets = [ + association["SubnetId"] + for nacl in network_acls + for association in nacl["Associations"] + if association["SubnetId"] + ] + changed = associate_nacl_to_subnets(client, module, default_nacl_id, subnets) return changed - subs_added = subnets_added(nacl_id, subnets, client, module) - if subs_added: - replace_network_acl_association(nacl_id, subs_added, client, module) - changed = True - subs_removed = subnets_removed(nacl_id, subnets, client, module) - if subs_removed: - default_nacl_id = find_default_vpc_nacl(vpc_id, client, module)[0] - replace_network_acl_association(default_nacl_id, subs_removed, client, module) - changed = True + + network_acls = describe_network_acls(client, NetworkAclIds=[nacl_id]) + current_subnets = [ + association["SubnetId"] + for nacl in network_acls + for association in nacl["Associations"] + if association["SubnetId"] + ] + subnets_added = [subnet for subnet in subnets_ids if subnet not in current_subnets] + subnets_removed = [subnet for subnet in current_subnets if subnet not in subnets_ids] + + if subnets_added: + changed |= associate_nacl_to_subnets(client, module, nacl_id, subnets_added) + if subnets_removed: + default_nacl_id = find_default_vpc_nacl(client, module, vpc_id) + changed |= associate_nacl_to_subnets(client, module, default_nacl_id, subnets_removed) + return changed -def nacls_changed(nacl, client, module): +def nacls_changed(client, module: AnsibleAWSModule, nacl_info: Dict[str, Any]) -> bool: changed = False - params = dict() - params["egress"] = module.params.get("egress") - params["ingress"] = module.params.get("ingress") - - nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"] - nacl = describe_network_acl(client, module) - entries = nacl["NetworkAcls"][0]["Entries"] - egress = [rule for rule in entries if rule["Egress"] is True and rule["RuleNumber"] < 32767] - ingress = [rule for rule in entries if rule["Egress"] is False and rule["RuleNumber"] < 32767] - if rules_changed(egress, params["egress"], True, nacl_id, client, module): - changed = True - if rules_changed(ingress, params["ingress"], False, nacl_id, client, module): - changed = True + entries = nacl_info["Entries"] + nacl_id = nacl_info["NetworkAclId"] + current_egress_rules = [rule for rule in entries if rule["Egress"] is True and rule["RuleNumber"] < 32767] + current_ingress_rules = [rule for rule in entries if rule["Egress"] is False and rule["RuleNumber"] < 32767] + + # Egress Rules + changed |= rules_changed(client, module, nacl_id, current_egress_rules, True) + # Ingress Rules + changed |= rules_changed(client, module, nacl_id, current_ingress_rules, False) return changed -def tags_changed(nacl_id, client, module): +def tags_changed(client, module: AnsibleAWSModule, nacl_id: str) -> bool: tags = module.params.get("tags") name = module.params.get("name") purge_tags = module.params.get("purge_tags") @@ -255,42 +253,102 @@ def tags_changed(nacl_id, client, module): ) -def rules_changed(aws_rules, param_rules, Egress, nacl_id, client, module): +def ansible_to_boto3_dict_rule(ansible_rule: List[Any], egress: bool) -> Dict[str, Any]: + boto3_rule = {} + if isinstance(ansible_rule, list): + boto3_rule["RuleNumber"] = ansible_rule[0] + boto3_rule["Protocol"] = str(PROTOCOL_NUMBERS[ansible_rule[1]]) + boto3_rule["RuleAction"] = ansible_rule[2] + boto3_rule["Egress"] = egress + if is_ipv6(ansible_rule[3]): + boto3_rule["Ipv6CidrBlock"] = ansible_rule[3] + else: + boto3_rule["CidrBlock"] = ansible_rule[3] + if icmp_present(ansible_rule): + boto3_rule["IcmpTypeCode"] = {"Type": int(ansible_rule[4]), "Code": int(ansible_rule[5])} + else: + if ansible_rule[6] or ansible_rule[7]: + boto3_rule["PortRange"] = {"From": ansible_rule[6], "To": ansible_rule[7]} + return boto3_rule + + +def diff_network_acl_rules( + new_rules: List[Dict[str, Any]], current_rules: List[Dict[str, Any]] +) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]: + rules_to_add = [] + rules_to_remove = [] + + # Find all rule to add + for rule in new_rules: + _match = False + for existing in current_rules: + if existing["RuleNumber"] == rule["RuleNumber"] and existing == rule: + _match = True + break + if not _match: + rules_to_add.append(rule) + + # Find all rule to remove + for existing in current_rules: + _match = False + for rule in new_rules: + if existing["RuleNumber"] == rule["RuleNumber"] and existing == rule: + _match = True + break + if not _match: + rules_to_remove.append(existing) + + return rules_to_add, rules_to_remove + + +def rules_changed( + client, module: AnsibleAWSModule, nacl_id: str, current_rules: List[Dict[str, Any]], egress: bool +) -> bool: changed = False - rules = list() - for entry in param_rules: - rules.append(process_rule_entry(entry, Egress)) - if rules == aws_rules: - return changed + new_rules = [] + + if egress: + new_rules += [ansible_to_boto3_dict_rule(r, egress=True) for r in module.params.get("egress")] else: - removed_rules = [x for x in aws_rules if x not in rules] - if removed_rules: - params = dict() - for rule in removed_rules: - params["NetworkAclId"] = nacl_id - params["RuleNumber"] = rule["RuleNumber"] - params["Egress"] = Egress - delete_network_acl_entry(params, client, module) - changed = True - added_rules = [x for x in rules if x not in aws_rules] - if added_rules: - for rule in added_rules: - rule["NetworkAclId"] = nacl_id - create_network_acl_entry(rule, client, module) - changed = True + new_rules += [ansible_to_boto3_dict_rule(r, egress=False) for r in module.params.get("ingress")] + + added_rules, removed_rules = diff_network_acl_rules(new_rules, current_rules) + if not added_rules and not removed_rules: + return changed + + # Added Rules + for rule in added_rules: + changed = True + if not module.check_mode: + rule_number = rule.pop("RuleNumber") + protocol = rule.pop("Protocol") + rule_action = rule.pop("RuleAction") + egress = rule.pop("Egress") + create_network_acl_entry( + client, + network_acl_id=nacl_id, + protocol=protocol, + egress=egress, + rule_action=rule_action, + rule_number=rule_number, + **rule, + ) + + # Removed Rules + for rule in removed_rules: + changed = True + if not module.check_mode: + delete_network_acl_entry(client, network_acl_id=nacl_id, rule_number=rule["RuleNumber"], egress=egress) + return changed -def is_ipv6(cidr): +def is_ipv6(cidr: str) -> bool: return ":" in cidr -def process_rule_entry(entry, Egress): - params = dict() - params["RuleNumber"] = entry[0] - params["Protocol"] = str(PROTOCOL_NUMBERS[entry[1]]) - params["RuleAction"] = entry[2] - params["Egress"] = Egress +def process_rule_entry(entry: List[Any]) -> Dict[str, Any]: + params = {} if is_ipv6(entry[3]): params["Ipv6CidrBlock"] = entry[3] else: @@ -300,275 +358,175 @@ def process_rule_entry(entry, Egress): else: if entry[6] or entry[7]: params["PortRange"] = {"From": entry[6], "To": entry[7]} - return params - - -def restore_default_associations(assoc_ids, default_nacl_id, client, module): - if assoc_ids: - params = dict() - params["NetworkAclId"] = default_nacl_id[0] - for assoc_id in assoc_ids: - params["AssociationId"] = assoc_id - restore_default_acl_association(params, client, module) - return True - -def construct_acl_entries(nacl, client, module): - for entry in module.params.get("ingress"): - params = process_rule_entry(entry, Egress=False) - params["NetworkAclId"] = nacl["NetworkAcl"]["NetworkAclId"] - create_network_acl_entry(params, client, module) - for rule in module.params.get("egress"): - params = process_rule_entry(rule, Egress=True) - params["NetworkAclId"] = nacl["NetworkAcl"]["NetworkAclId"] - create_network_acl_entry(params, client, module) + return params -# Module invocations -def setup_network_acl(client, module): +def construct_acl_entries(client, module: AnsibleAWSModule, nacl_id: str) -> bool: changed = False - nacl = describe_network_acl(client, module) - if not nacl["NetworkAcls"]: - tags = {} - if module.params.get("name"): - tags["Name"] = module.params.get("name") - tags.update(module.params.get("tags") or {}) - nacl = create_network_acl(module.params.get("vpc_id"), client, module, tags) - nacl_id = nacl["NetworkAcl"]["NetworkAclId"] - subnets = subnets_to_associate(nacl, client, module) - replace_network_acl_association(nacl_id, subnets, client, module) - construct_acl_entries(nacl, client, module) + # Process list entries + for entry in module.params.get("ingress"): changed = True - return changed, nacl["NetworkAcl"]["NetworkAclId"] - else: - changed = False - nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"] - changed |= subnets_changed(nacl, client, module) - changed |= nacls_changed(nacl, client, module) - changed |= tags_changed(nacl_id, client, module) - return changed, nacl_id + if not module.check_mode: + create_network_acl_entry( + client, + network_acl_id=nacl_id, + protocol=str(PROTOCOL_NUMBERS[entry[1]]), + egress=False, + rule_action=entry[2], + rule_number=entry[0], + **process_rule_entry(entry), + ) + for entry in module.params.get("egress"): + changed = True + if not module.check_mode: + create_network_acl_entry( + client, + network_acl_id=nacl_id, + protocol=str(PROTOCOL_NUMBERS[entry[1]]), + egress=True, + rule_action=entry[2], + rule_number=entry[0], + **process_rule_entry(entry), + ) + + return changed -def remove_network_acl(client, module): +def associate_nacl_to_subnets(client, module: AnsibleAWSModule, nacl_id: str, subnets_ids: List[str]) -> bool: changed = False - result = dict() - nacl = describe_network_acl(client, module) - if nacl["NetworkAcls"]: - nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"] - vpc_id = nacl["NetworkAcls"][0]["VpcId"] - associations = nacl["NetworkAcls"][0]["Associations"] - assoc_ids = [a["NetworkAclAssociationId"] for a in associations] - default_nacl_id = find_default_vpc_nacl(vpc_id, client, module) - if not default_nacl_id: - result = {vpc_id: "Default NACL ID not found - Check the VPC ID"} - return changed, result - if restore_default_associations(assoc_ids, default_nacl_id, client, module): - delete_network_acl(nacl_id, client, module) - changed = True - result[nacl_id] = "Successfully deleted" - return changed, result - if not assoc_ids: - delete_network_acl(nacl_id, client, module) + if subnets_ids: + network_acls = describe_network_acls(client, Filters=[{"Name": "association.subnet-id", "Values": subnets_ids}]) + associations = [ + association["NetworkAclAssociationId"] + for nacl in network_acls + for association in nacl["Associations"] + if association["SubnetId"] in subnets_ids + ] + for association_id in associations: changed = True - result[nacl_id] = "Successfully deleted" - return changed, result - return changed, result - + if not module.check_mode: + replace_network_acl_association(client, network_acl_id=nacl_id, association_id=association_id) + return changed -# Boto3 client methods -@AWSRetry.jittered_backoff() -def _create_network_acl(client, *args, **kwargs): - return client.create_network_acl(*args, **kwargs) +def ensure_present(client, module: AnsibleAWSModule) -> None: + changed = False + nacl = describe_network_acl(client, module) + nacl_id = None + subnets_ids = [] + subnets = module.params.get("subnets") + if subnets: + subnets_ids = find_subnets_ids(client, module, subnets) -def create_network_acl(vpc_id, client, module, tags): - params = dict(VpcId=vpc_id) - if tags: - params["TagSpecifications"] = boto3_tag_specifications(tags, ["network-acl"]) - try: + if not nacl: if module.check_mode: - nacl = dict(NetworkAcl=dict(NetworkAclId="nacl-00000000")) - else: - nacl = _create_network_acl(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - return nacl - - -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _create_network_acl_entry(client, *args, **kwargs): - return client.create_network_acl_entry(*args, **kwargs) - + module.exit_json(changed=True, msg="Would have created Network ACL if not in check mode.") -def create_network_acl_entry(params, client, module): - try: - if not module.check_mode: - _create_network_acl_entry(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) + # Create Network ACL + tags = {} + name = module.params.get("name") + vpc_id = module.params.get("vpc_id") + if name: + tags["Name"] = name + if module.params.get("tags"): + tags.update(module.params.get("tags")) + nacl = create_network_acl(client, vpc_id, tags) + changed = True + # Associate Subnets to Network ACL + nacl_id = nacl["NetworkAclId"] + associate_nacl_to_subnets(client, module, nacl_id, subnets_ids) -@AWSRetry.jittered_backoff() -def _delete_network_acl(client, *args, **kwargs): - return client.delete_network_acl(*args, **kwargs) + # Create Network ACL entries + construct_acl_entries(client, module, nacl_id) + else: + nacl_id = nacl["NetworkAclId"] + changed |= subnets_changed(client, module, nacl_id, subnets_ids) + changed |= nacls_changed(client, module, nacl) + changed |= tags_changed(client, module, nacl_id) + module.exit_json(changed=changed, nacl_id=nacl_id) -def delete_network_acl(nacl_id, client, module): - try: - if not module.check_mode: - _delete_network_acl(client, NetworkAclId=nacl_id) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) +def ensure_absent(client, module: AnsibleAWSModule) -> None: + changed = False + result = {} + nacl = describe_network_acl(client, module) + if not nacl: + module.exit_json(changed=changed) -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _delete_network_acl_entry(client, *args, **kwargs): - return client.delete_network_acl_entry(*args, **kwargs) + nacl_id = nacl["NetworkAclId"] + vpc_id = nacl["VpcId"] + associations = nacl["Associations"] + assoc_ids = [a["NetworkAclAssociationId"] for a in associations] + # Find default NACL associated to the VPC + default_nacl_id = find_default_vpc_nacl(client, module, vpc_id) + if not default_nacl_id: + module.exit_json(changed=changed, msg="Default NACL ID not found - Check the VPC ID") -def delete_network_acl_entry(params, client, module): - try: + # Replace Network ACL association + for assoc_id in assoc_ids: + changed = True if not module.check_mode: - _delete_network_acl_entry(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - + replace_network_acl_association(client, network_acl_id=default_nacl_id, association_id=assoc_id) -@AWSRetry.jittered_backoff() -def _describe_network_acls(client, **kwargs): - return client.describe_network_acls(**kwargs) + # Delete Network ACL + changed = True + if module.check_mode: + module.exit_json(changed=changed, msg=f"Would have deleted Network ACL id '{nacl_id}' if not in check mode.") + changed = delete_network_acl(client, network_acl_id=nacl_id) + module.exit_json(changed=changed, msg=f"Network ACL id '{nacl_id}' successfully deleted.") -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _describe_network_acls_retry_missing(client, **kwargs): - return client.describe_network_acls(**kwargs) - -def describe_acl_associations(subnets, client, module): - if not subnets: - return [] - try: - results = _describe_network_acls_retry_missing( - client, Filters=[{"Name": "association.subnet-id", "Values": subnets}] - ) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - associations = results["NetworkAcls"][0]["Associations"] - return [a["NetworkAclAssociationId"] for a in associations if a["SubnetId"] in subnets] - - -def describe_network_acl(client, module): +def describe_network_acl(client, module: AnsibleAWSModule) -> Optional[Dict[str, Any]]: + nacl_id = module.params.get("nacl_id") + name = module.params.get("name") try: - if module.params.get("nacl_id"): - nacl = _describe_network_acls( - client, Filters=[{"Name": "network-acl-id", "Values": [module.params.get("nacl_id")]}] - ) + if nacl_id: + filters = [{"Name": "network-acl-id", "Values": [nacl_id]}] else: - nacl = _describe_network_acls(client, Filters=[{"Name": "tag:Name", "Values": [module.params.get("name")]}]) - except botocore.exceptions.ClientError as e: + filters = [{"Name": "tag:Name", "Values": [name]}] + network_acls = describe_network_acls(client, Filters=filters) + return None if not network_acls else network_acls[0] + except AnsibleEC2Error as e: module.fail_json_aws(e) - return nacl -def find_acl_by_id(nacl_id, client, module): +def find_default_vpc_nacl(client, module: AnsibleAWSModule, vpc_id: str) -> Optional[str]: + default_nacl_id = None try: - return _describe_network_acls_retry_missing(client, NetworkAclIds=[nacl_id]) - except botocore.exceptions.ClientError as e: + for nacl in describe_network_acls(client, Filters=[{"Name": "vpc-id", "Values": [vpc_id]}]): + if nacl.get("IsDefault", False): + default_nacl_id = nacl["NetworkAclId"] + break + except AnsibleEC2Error as e: module.fail_json_aws(e) + return default_nacl_id -def find_default_vpc_nacl(vpc_id, client, module): +def find_subnets_ids(client, module: AnsibleAWSModule, subnets_ids_or_names: List[str]) -> List[str]: + subnets_ids = [] + subnets_names = [] try: - response = _describe_network_acls_retry_missing(client, Filters=[{"Name": "vpc-id", "Values": [vpc_id]}]) - except botocore.exceptions.ClientError as e: + # Find Subnets by ID + subnets = describe_subnets(client, Filters=[{"Name": "subnet-id", "Values": subnets_ids_or_names}]) + subnets_ids += [subnet["SubnetId"] for subnet in subnets] + subnets_names += [tag["Value"] for subnet in subnets for tag in subnet.get("Tags", []) if tag["Key"] == "Name"] + + # Find Subnets by Name + subnets = describe_subnets(client, Filters=[{"Name": "tag:Name", "Values": subnets_ids_or_names}]) + subnets_ids += [subnet["SubnetId"] for subnet in subnets] + subnets_names += [tag["Value"] for subnet in subnets for tag in subnet.get("Tags", []) if tag["Key"] == "Name"] + + unexisting_subnets = [s for s in subnets_ids_or_names if s not in subnets_names + subnets_ids] + if unexisting_subnets: + module.fail_json(msg=f"The following subnets do not exist: {unexisting_subnets}") + return subnets_ids + except AnsibleEC2Error as e: module.fail_json_aws(e) - nacls = response["NetworkAcls"] - return [n["NetworkAclId"] for n in nacls if n["IsDefault"] is True] - - -def find_subnet_ids_by_nacl_id(nacl_id, client, module): - try: - results = _describe_network_acls_retry_missing( - client, Filters=[{"Name": "association.network-acl-id", "Values": [nacl_id]}] - ) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - if results["NetworkAcls"]: - associations = results["NetworkAcls"][0]["Associations"] - return [s["SubnetId"] for s in associations if s["SubnetId"]] - else: - return [] - - -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _replace_network_acl_association(client, *args, **kwargs): - return client.replace_network_acl_association(*args, **kwargs) - - -def replace_network_acl_association(nacl_id, subnets, client, module): - params = dict() - params["NetworkAclId"] = nacl_id - for association in describe_acl_associations(subnets, client, module): - params["AssociationId"] = association - try: - if not module.check_mode: - _replace_network_acl_association(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - - -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _replace_network_acl_entry(client, *args, **kwargs): - return client.replace_network_acl_entry(*args, **kwargs) - - -def replace_network_acl_entry(entries, Egress, nacl_id, client, module): - for entry in entries: - params = entry - params["NetworkAclId"] = nacl_id - try: - if not module.check_mode: - _replace_network_acl_entry(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - - -@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"]) -def _replace_network_acl_association(client, *args, **kwargs): - return client.replace_network_acl_association(*args, **kwargs) - - -def restore_default_acl_association(params, client, module): - try: - if not module.check_mode: - _replace_network_acl_association(client, **params) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - - -@AWSRetry.jittered_backoff() -def _describe_subnets(client, *args, **kwargs): - return client.describe_subnets(*args, **kwargs) - - -def subnets_to_associate(nacl, client, module): - params = list(module.params.get("subnets")) - if not params: - return [] - all_found = [] - if any(x.startswith("subnet-") for x in params): - try: - subnets = _describe_subnets(client, Filters=[{"Name": "subnet-id", "Values": params}]) - all_found.extend(subnets.get("Subnets", [])) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - if len(params) != len(all_found): - try: - subnets = _describe_subnets(client, Filters=[{"Name": "tag:Name", "Values": params}]) - all_found.extend(subnets.get("Subnets", [])) - except botocore.exceptions.ClientError as e: - module.fail_json_aws(e) - return list(set(s["SubnetId"] for s in all_found if s.get("SubnetId"))) def main(): @@ -576,30 +534,32 @@ def main(): vpc_id=dict(), name=dict(), nacl_id=dict(), - subnets=dict(required=False, type="list", default=list(), elements="str"), + subnets=dict(required=False, type="list", default=[], elements="str"), tags=dict(required=False, type="dict", aliases=["resource_tags"]), purge_tags=dict(required=False, type="bool", default=True), ingress=dict(required=False, type="list", default=list(), elements="list"), egress=dict(required=False, type="list", default=list(), elements="list"), state=dict(default="present", choices=["present", "absent"]), ) + + mutually_exclusive = [ + ["name", "nacl_id"], + ] + module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, required_one_of=[["name", "nacl_id"]], required_if=[["state", "present", ["vpc_id"]]], + mutually_exclusive=mutually_exclusive, ) - state = module.params.get("state").lower() - client = module.client("ec2") - invocations = { - "present": setup_network_acl, - "absent": remove_network_acl, - } - (changed, results) = invocations[state](client, module) - module.exit_json(changed=changed, nacl_id=results) + if module.params.get("state") == "present": + ensure_present(client, module) + else: + ensure_absent(client, module) if __name__ == "__main__": diff --git a/plugins/modules/ec2_vpc_nacl_info.py b/plugins/modules/ec2_vpc_nacl_info.py index d95508a894e..1505062e01c 100644 --- a/plugins/modules/ec2_vpc_nacl_info.py +++ b/plugins/modules/ec2_vpc_nacl_info.py @@ -102,15 +102,16 @@ sample: [[100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]] """ -try: - import botocore -except ImportError: - pass # caught by AnsibleAWSModule +from typing import Any +from typing import Dict +from typing import List +from typing import Union 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 AnsibleAWSError +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_network_acls +from ansible_collections.amazon.aws.plugins.module_utils.exceptions import is_ansible_aws_error_code 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 @@ -121,55 +122,60 @@ PROTOCOL_NAMES = {"-1": "all", "1": "icmp", "6": "tcp", "17": "udp"} -def list_ec2_vpc_nacls(connection, module): +def format_nacl(nacl: Dict[str, Any]) -> Dict[str, Any]: + # Turn the boto3 result into ansible friendly snake cases + nacl = camel_dict_to_snake_dict(nacl) + + # convert boto3 tags list into ansible dict + if "tags" in nacl: + nacl["tags"] = boto3_tag_list_to_ansible_dict(nacl["tags"], "key", "value") + + # Convert NACL entries + if "entries" in nacl: + nacl["egress"] = [ + nacl_entry_to_list(entry) for entry in nacl["entries"] if entry["rule_number"] < 32767 and entry["egress"] + ] + nacl["ingress"] = [ + nacl_entry_to_list(entry) + for entry in nacl["entries"] + if entry["rule_number"] < 32767 and not entry["egress"] + ] + del nacl["entries"] + + # Read subnets from NACL Associations + if "associations" in nacl: + nacl["subnets"] = [a["subnet_id"] for a in nacl["associations"]] + del nacl["associations"] + + # Read Network ACL id + if "network_acl_id" in nacl: + nacl["nacl_id"] = nacl["network_acl_id"] + del nacl["network_acl_id"] + + return nacl + + +def list_ec2_vpc_nacls(connection, module: AnsibleAWSModule) -> None: nacl_ids = module.params.get("nacl_ids") - filters = ansible_dict_to_boto3_filter_list(module.params.get("filters")) + filters = module.params.get("filters") - if nacl_ids is None: - nacl_ids = [] + params = {} + if filters: + params["Filters"] = ansible_dict_to_boto3_filter_list(filters) + if nacl_ids: + params["NetworkAclIds"] = nacl_ids try: - nacls = connection.describe_network_acls(aws_retry=True, NetworkAclIds=nacl_ids, Filters=filters) - except is_boto3_error_code("InvalidNetworkAclID.NotFound"): - module.fail_json(msg="Unable to describe ACL. NetworkAcl does not exist") - except ( - botocore.exceptions.ClientError, - botocore.exceptions.BotoCoreError, - ) as e: # pylint: disable=duplicate-except + snaked_nacls = [format_nacl(nacl) for nacl in describe_network_acls(connection, **params)] + except is_ansible_aws_error_code("InvalidNetworkAclID.NotFound"): + module.fail_json(msg="Unable to describe ACL. NetworkAcl does not exist") + except AnsibleAWSError as e: # pylint: disable=duplicate-except module.fail_json_aws(e, msg=f"Unable to describe network ACLs {nacl_ids}") - # Turn the boto3 result in to ansible_friendly_snaked_names - snaked_nacls = [] - for nacl in nacls["NetworkAcls"]: - snaked_nacls.append(camel_dict_to_snake_dict(nacl)) - - # Turn the boto3 result in to ansible friendly tag dictionary - for nacl in snaked_nacls: - if "tags" in nacl: - nacl["tags"] = boto3_tag_list_to_ansible_dict(nacl["tags"], "key", "value") - if "entries" in nacl: - nacl["egress"] = [ - nacl_entry_to_list(entry) - for entry in nacl["entries"] - if entry["rule_number"] < 32767 and entry["egress"] - ] - nacl["ingress"] = [ - nacl_entry_to_list(entry) - for entry in nacl["entries"] - if entry["rule_number"] < 32767 and not entry["egress"] - ] - del nacl["entries"] - if "associations" in nacl: - nacl["subnets"] = [a["subnet_id"] for a in nacl["associations"]] - del nacl["associations"] - if "network_acl_id" in nacl: - nacl["nacl_id"] = nacl["network_acl_id"] - del nacl["network_acl_id"] - module.exit_json(nacls=snaked_nacls) -def nacl_entry_to_list(entry): +def nacl_entry_to_list(entry: Dict[str, Any]) -> List[Union[str, int, None]]: # entry list format # [ rule_num, protocol name or number, allow or deny, ipv4/6 cidr, icmp type, icmp code, port from, port to] elist = [] @@ -217,7 +223,7 @@ def main(): supports_check_mode=True, ) - connection = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff()) + connection = module.client("ec2") list_ec2_vpc_nacls(connection, module) diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/ingress_and_egress.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/ingress_and_egress.yml index 875e7f0b2d7..8431316de1c 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/ingress_and_egress.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/ingress_and_egress.yml @@ -1,6 +1,6 @@ # ============================================================ - block: - - name: create ingress and egress rules using subnet IDs + - name: Create ingress and egress rules using subnet IDs ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -16,19 +16,19 @@ state: 'present' register: nacl - - name: assert the network acl was created + - name: Assert the network acl was created assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') - - name: get network ACL facts + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -37,7 +37,7 @@ # ============================================================ - - name: remove an ingress rule + - name: Remove an ingress rule ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -52,19 +52,19 @@ state: 'present' register: nacl - - name: assert the network acl changed + - name: Assert the network acl changed assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') - - name: get network ACL facts + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -73,7 +73,7 @@ # ============================================================ - - name: remove the egress rule + - name: Remove the egress rule ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -87,19 +87,19 @@ state: 'present' register: nacl - - name: assert the network acl changed + - name: Assert the network acl changed assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') - - name: get network ACL facts + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -108,7 +108,7 @@ # ============================================================ - - name: add egress rules + - name: Add egress rules ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -124,19 +124,19 @@ state: 'present' register: nacl - - name: assert the network acl changed + - name: Assert the network acl changed assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') - - name: get network ACL facts + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -145,14 +145,14 @@ # ============================================================ - - name: remove the network ACL + - name: Remove the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" state: absent register: nacl - - name: assert nacl was removed + - name: Assert nacl was removed assert: that: - nacl.changed diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/ipv6.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/ipv6.yml index 1366971613a..c5405cc40d5 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/ipv6.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/ipv6.yml @@ -2,7 +2,7 @@ # ============================================================ - - name: create ingress and egress rules using subnet names + - name: Create ingress and egress rules using subnet names ec2_vpc_nacl: vpc_id: "{{ vpc_ipv6_id }}" name: "{{ nacl_name }}" @@ -18,14 +18,16 @@ - [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null] state: 'present' register: nacl - - assert: + + - name: Assert that module returned the Network ACL id + assert: that: - nacl.nacl_id - set_fact: nacl_id: "{{ nacl.nacl_id }}" - - name: add ipv6 entries + - name: Add ipv6 entries ec2_vpc_nacl: vpc_id: "{{ vpc_ipv6_id }}" name: "{{ nacl_name }}" @@ -45,25 +47,26 @@ state: 'present' register: nacl - - assert: + - name: Assert that module reported change while the Network ACL remained unchanged + assert: that: - nacl.changed - nacl.nacl_id == nacl_id - - name: get network ACL facts (test that it works with ipv6 entries) + - name: Get network ACL facts (test that it works with ipv6 entries) ec2_vpc_nacl_info: nacl_ids: - "{{ nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 - nacl_facts.nacls[0].ingress | length == 5 - nacl_facts.nacls[0].egress | length == 2 - - name: purge ingress entries + - name: Purge ingress entries ec2_vpc_nacl: vpc_id: "{{ vpc_ipv6_id }}" name: "{{ nacl_name }}" @@ -78,12 +81,13 @@ state: 'present' register: nacl - - assert: + - name: Assert that module reported change while the Network ACL remained unchanged + assert: that: - nacl.changed - nacl.nacl_id == nacl_id - - name: purge egress entries + - name: Purge egress entries ec2_vpc_nacl: vpc_id: "{{ vpc_ipv6_id }}" name: "{{ nacl_name }}" @@ -96,17 +100,18 @@ state: 'present' register: nacl - - assert: + - name: Assert that module reported change + assert: that: - nacl.changed - - name: get network ACL facts (test that removed entries are gone) + - name: Get network ACL facts (test that removed entries are gone) ec2_vpc_nacl_info: nacl_ids: - "{{ nacl_id }}" register: nacl_facts - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -115,10 +120,10 @@ always: - - name: remove network ACL + - name: Remove network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_ipv6_id }}" name: "{{ nacl_name }}" state: absent register: removed_acl - ignore_errors: yes + ignore_errors: true diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml index 36c7ab2d8bb..e58bf6485b8 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml @@ -11,34 +11,34 @@ # ============================================================ - - name: test without any parameters + - name: Test without any parameters ec2_vpc_nacl: register: result - ignore_errors: yes + ignore_errors: true - - name: assert required parameters + - name: Assert required parameters assert: that: - result.failed - "result.msg == 'one of the following is required: name, nacl_id'" - - name: get network ACL info without any parameters + - name: Get network ACL info without any parameters ec2_vpc_nacl_info: register: nacl_facts - - name: assert we don't error + - name: Assert we don't error assert: that: - nacl_facts is succeeded - - name: get network ACL info with invalid ID + - name: Get network ACL info with invalid ID ec2_vpc_nacl_info: nacl_ids: - 'acl-000000000000' register: nacl_facts - ignore_errors: yes + ignore_errors: true - - name: assert message mentions missing ACLs + - name: Assert message mentions missing ACLs assert: that: - nacl_facts is failed @@ -46,7 +46,7 @@ # ============================================================ - - name: fetch AZ availability + - name: Fetch AZ availability aws_az_info: register: az_info @@ -54,14 +54,14 @@ assert: that: az_info.availability_zones | length >= 2 - - name: pick AZs + - name: Pick AZs set_fact: az_one: '{{ az_info.availability_zones[0].zone_name }}' az_two: '{{ az_info.availability_zones[1].zone_name }}' # ============================================================ - - name: create a VPC + - name: Create a VPC ec2_vpc_net: cidr_block: "{{ vpc_cidr }}" name: "{{ vpc_name }}" @@ -72,7 +72,7 @@ set_fact: vpc_id: "{{ vpc.vpc.id }}" - - name: create subnets + - name: Create subnets ec2_vpc_subnet: cidr: "{{ item.cidr }}" az: "{{ item.az }}" @@ -95,17 +95,17 @@ name: "{{ subnet_name }}-4" register: subnets - - name: set helpful facts about subnets + - name: Set helpful facts about subnets set_fact: subnet_ids: "{{ subnets | community.general.json_query('results[*].subnet.id') }}" subnet_names: "{{ subnets | community.general.json_query('results[*].subnet.tags.Name') }}" - - name: create VPC for IPv6 tests + - name: Create VPC for IPv6 tests ec2_vpc_net: cidr_block: "{{ vpc_ipv6_cidr }}" name: "{{ vpc_ipv6_name }}" state: present - ipv6_cidr: yes + ipv6_cidr: true register: vpc_result - set_fact: vpc_ipv6_id: "{{ vpc_result.vpc.id }}" @@ -114,7 +114,7 @@ vars: _ipv6_cidr: "{{ vpc_result.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block }}" - - name: create subnet with IPv6 + - name: Create subnet with IPv6 ec2_vpc_subnet: cidr: "{{ vpc_ipv6_cidr }}" vpc_id: "{{ vpc_ipv6_id }}" @@ -124,30 +124,28 @@ Name: "{{ subnet_name }}-ipv6" # ============================================================ - - - include_tasks: tasks/subnet_ids.yml - - - include_tasks: tasks/subnet_names.yml - - - include_tasks: tasks/tags.yml - - - include_tasks: tasks/ingress_and_egress.yml - - - include_tasks: tasks/ipv6.yml + - name: Run individual tasks + ansible.builtin.include_tasks: "tasks/{{ item }}.yml" + with_items: + - subnet_ids + - subnet_names + - tags + - ingress_and_egress + - ipv6 # ============================================================ always: - - name: remove network ACL + - name: Remove network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" state: absent register: removed_acl - ignore_errors: yes + ignore_errors: true - - name: remove subnets + - name: Remove subnets ec2_vpc_subnet: cidr: "{{ item.cidr }}" vpc_id: "{{ item.vpc_id | default(vpc_id) }}" @@ -159,14 +157,14 @@ - cidr: "{{ subnet_4 }}" - cidr: "{{ vpc_ipv6_cidr }}" vpc_id: "{{ vpc_ipv6_id }}" - ignore_errors: yes + ignore_errors: true register: removed_subnets - - name: remove the VPCs + - name: Remove the VPCs ec2_vpc_net: vpc_id: "{{ item }}" state: absent - ignore_errors: yes + ignore_errors: true register: removed_vpc with_items: - '{{ vpc_id }}' diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_ids.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_ids.yml index 4e1affa1f34..42a6205f696 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_ids.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_ids.yml @@ -1,6 +1,6 @@ # ============================================================ -- name: create ingress and egress rules using subnet IDs +- name: Create ingress and egress rules using subnet IDs ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -19,19 +19,19 @@ - set_fact: nacl_id: "{{ nacl.nacl_id }}" -- name: assert the network acl was created +- name: Assert the network acl was created assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl_id }}" register: nacl_facts -- name: assert the nacl has the correct attributes +- name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -44,7 +44,7 @@ # ============================================================ -- name: test idempotence +- name: Test idempotence ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -60,27 +60,27 @@ state: 'present' register: nacl -- name: assert the network acl already existed +- name: Assert the network acl already existed assert: that: - not nacl.changed - nacl.nacl_id == nacl_id - nacl.nacl_id.startswith('acl-') -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts_idem -- name: assert the facts are the same as before +- name: Assert the facts are the same as before assert: that: - nacl_facts_idem == nacl_facts # ============================================================ -- name: remove a subnet from the network ACL +- name: Remove a subnet from the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -99,20 +99,20 @@ state: 'present' register: nacl -- name: assert the network ACL changed +- name: Assert the network ACL changed assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') - nacl.nacl_id == nacl_id -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_id: - "{{ nacl.nacl_id }}" register: nacl_facts -- name: assert the nacl has the correct attributes +- name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -125,7 +125,7 @@ # ============================================================ -- name: remove the network ACL +- name: Remove the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -137,7 +137,7 @@ that: - nacl.changed -- name: re-remove the network ACL by name (test idempotency) +- name: Re-remove the network ACL by name (test idempotency) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -148,14 +148,14 @@ that: - nacl is not changed -- name: re-remove the network ACL by id (test idempotency) +- name: Re-remove the network ACL by id (test idempotency) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" nacl_id: "{{ nacl_id }}" state: absent register: nacl -- name: assert nacl was removed +- name: Assert nacl was removed assert: that: - nacl is not changed diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_names.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_names.yml index 4db7e1b2068..ad984436ae5 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_names.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/subnet_names.yml @@ -1,6 +1,6 @@ # ============================================================ -- name: create ingress and egress rules using subnet names +- name: Create ingress and egress rules using subnet names ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -19,19 +19,19 @@ - set_fact: nacl_id: "{{ nacl.nacl_id }}" -- name: assert the network acl was created +- name: Assert the network acl was created assert: that: - nacl.changed - nacl.nacl_id.startswith('acl-') -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl_id }}" register: nacl_facts -- name: assert the nacl has the correct attributes +- name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -43,7 +43,7 @@ # ============================================================ -- name: test idempotence +- name: Test idempotence ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -59,27 +59,27 @@ state: 'present' register: nacl -- name: assert the network acl already existed +- name: Assert the network acl already existed assert: that: - not nacl.changed - nacl.nacl_id == nacl_id - nacl.nacl_id.startswith('acl-') -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts_idem -- name: assert the facts are the same as before +- name: Assert the facts are the same as before assert: that: - nacl_facts_idem == nacl_facts # ============================================================ -- name: remove a subnet from the network ACL +- name: Remove a subnet from the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -98,20 +98,20 @@ state: 'present' register: nacl -- name: assert the network ACL changed +- name: Assert the network ACL changed assert: that: - nacl.changed - nacl.nacl_id == nacl_id - nacl.nacl_id.startswith('acl-') -- name: get network ACL facts +- name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_facts -- name: assert the nacl has the correct attributes +- name: Assert the nacl has the correct attributes assert: that: - nacl_facts.nacls | length == 1 @@ -123,14 +123,14 @@ # ============================================================ -- name: remove the network ACL +- name: Remove the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" state: absent register: nacl -- name: assert nacl was removed +- name: Assert nacl was removed assert: that: - nacl.changed diff --git a/tests/integration/targets/ec2_vpc_nacl/tasks/tags.yml b/tests/integration/targets/ec2_vpc_nacl/tasks/tags.yml index da3ad71dda3..bfcc086c812 100644 --- a/tests/integration/targets/ec2_vpc_nacl/tasks/tags.yml +++ b/tests/integration/targets/ec2_vpc_nacl/tasks/tags.yml @@ -30,7 +30,7 @@ # ============================================================ - - name: create a network ACL using subnet IDs + - name: Create a network ACL using subnet IDs ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -38,7 +38,7 @@ state: 'present' register: nacl - - name: assert the network acl was created + - name: Assert the network acl was created assert: that: - nacl.changed @@ -48,13 +48,13 @@ set_fact: nacl_id: '{{ nacl.nacl_id }}' - - name: get network ACL facts + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl_id }}" register: nacl_info - - name: assert the nacl has the correct attributes + - name: Assert the nacl has the correct attributes assert: that: - nacl_info.nacls[0].nacl_id == nacl_id @@ -62,7 +62,7 @@ # ============================================================ - - name: (check) add tags + - name: Add tags (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -72,13 +72,13 @@ register: nacl check_mode: True - - name: assert would change + - name: Assert would change assert: that: - nacl is changed - nacl.nacl_id == nacl_id - - name: add tags + - name: Add tags ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -86,13 +86,14 @@ tags: "{{ first_tags }}" state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify the tags were added + - name: Verify the tags were added assert: that: - nacl is changed @@ -100,7 +101,7 @@ - nacl_info.nacls[0].nacl_id == nacl_id - nacl_info.nacls[0].tags == ( first_tags | combine(name_tags) ) - - name: (check) add tags - IDEMPOTENCY + - name: Add tags - IDEMPOTENCY (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -110,13 +111,13 @@ register: nacl check_mode: True - - name: assert would not change + - name: Assert would not change assert: that: - nacl is not changed - nacl.nacl_id == nacl_id - - name: add tags - IDEMPOTENCY + - name: Add tags - IDEMPOTENCY ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -124,13 +125,14 @@ tags: "{{ first_tags }}" state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify no change + - name: Verify no change assert: that: - nacl is not changed @@ -140,13 +142,13 @@ # ============================================================ - - name: get network ACL facts by filter + - name: Get network ACL facts by filter ec2_vpc_nacl_info: filters: "tag:Name": "{{ nacl_name }}" register: nacl_info - - name: assert the facts are the same as before + - name: Assert the facts are the same as before assert: that: - nacl_info.nacls | length == 1 @@ -155,7 +157,7 @@ # ============================================================ - - name: (check) modify tags with purge + - name: Modify tags with purge (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -165,13 +167,13 @@ register: nacl check_mode: True - - name: assert would change + - name: Assert would change assert: that: - nacl is changed - nacl.nacl_id == nacl_id - - name: modify tags with purge + - name: Modify tags with purge ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -179,13 +181,14 @@ tags: "{{ second_tags }}" state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify the tags were added + - name: Verify the tags were added assert: that: - nacl is changed @@ -193,7 +196,7 @@ - nacl_info.nacls[0].nacl_id == nacl_id - nacl_info.nacls[0].tags == ( second_tags | combine(name_tags) ) - - name: (check) modify tags with purge - IDEMPOTENCY + - name: Modify tags with purge - IDEMPOTENCY (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -203,13 +206,13 @@ register: nacl check_mode: True - - name: assert would not change + - name: Assert would not change assert: that: - nacl is not changed - nacl.nacl_id == nacl_id - - name: modify tags with purge - IDEMPOTENCY + - name: Modify tags with purge - IDEMPOTENCY ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -217,13 +220,14 @@ tags: "{{ second_tags }}" state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify no change + - name: Verify no change assert: that: - nacl is not changed @@ -233,7 +237,7 @@ # ============================================================ - - name: (check) modify tags without purge + - name: Modify tags without purge (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -244,13 +248,13 @@ register: nacl check_mode: True - - name: assert would change + - name: Assert would change assert: that: - nacl is changed - nacl.nacl_id == nacl_id - - name: modify tags without purge + - name: Modify tags without purge ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -259,13 +263,14 @@ state: 'present' purge_tags: False register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify the tags were added + - name: Verify the tags were added assert: that: - nacl is changed @@ -273,7 +278,7 @@ - nacl_info.nacls[0].nacl_id == nacl_id - nacl_info.nacls[0].tags == ( final_tags | combine(name_tags) ) - - name: (check) modify tags without purge - IDEMPOTENCY + - name: Modify tags without purge - IDEMPOTENCY (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -284,13 +289,13 @@ register: nacl check_mode: True - - name: assert would not change + - name: Assert would not change assert: that: - nacl is not changed - nacl.nacl_id == nacl_id - - name: modify tags without purge - IDEMPOTENCY + - name: Modify tags without purge - IDEMPOTENCY ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -299,13 +304,14 @@ state: 'present' purge_tags: False register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify no change + - name: Verify no change assert: that: - nacl is not changed @@ -315,7 +321,7 @@ # ============================================================ - - name: (check) No change to tags without setting tags + - name: No change to tags without setting tags (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -324,7 +330,7 @@ register: nacl check_mode: True - - name: assert would change + - name: Assert would change assert: that: - nacl is not changed @@ -337,13 +343,14 @@ subnets: "{{ subnet_ids }}" state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify the tags were added + - name: Verify the tags were added assert: that: - nacl is not changed @@ -353,7 +360,7 @@ # ============================================================ - - name: (check) remove non name tags + - name: Remove non name tags (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -363,13 +370,13 @@ register: nacl check_mode: True - - name: assert would change + - name: Assert would change assert: that: - nacl is changed - nacl.nacl_id == nacl_id - - name: remove non name tags + - name: Remove non name tags ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -377,13 +384,14 @@ tags: {} state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify the tags were added + - name: Verify the tags were added assert: that: - nacl is changed @@ -391,7 +399,7 @@ - nacl_info.nacls[0].nacl_id == nacl_id - nacl_info.nacls[0].tags == name_tags - - name: (check) remove non name tags - IDEMPOTENCY + - name: Remove non name tags - IDEMPOTENCY (check mode) ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -401,13 +409,13 @@ register: nacl check_mode: True - - name: assert would not change + - name: Assert would not change assert: that: - nacl is not changed - nacl.nacl_id == nacl_id - - name: remove non name tags - IDEMPOTENCY + - name: Remove non name tags - IDEMPOTENCY ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" @@ -415,13 +423,14 @@ tags: {} state: 'present' register: nacl - - name: get network ACL facts + + - name: Get network ACL facts ec2_vpc_nacl_info: nacl_ids: - "{{ nacl.nacl_id }}" register: nacl_info - - name: verify no change + - name: Verify no change assert: that: - nacl is not changed @@ -432,14 +441,14 @@ # ============================================================ always: - - name: remove the network ACL + - name: Remove the network ACL ec2_vpc_nacl: vpc_id: "{{ vpc_id }}" name: "{{ nacl_name }}" state: absent register: nacl - - name: assert nacl was removed + - name: Assert nacl was removed assert: that: - nacl.changed