Repository: getmoto/moto
Pull request #8173 (2024-09-28 19:48:50)

EC2: create_network_acl_entry() now supports the Ipv6CidrBlock-parameter
With this parameter now returning correctly, `terraform` no longer feels the need to recreate NetworkACL entries every time.

And because of that, we can run the same test steps (apply / plan / delete) for all terraform tests, including EC2.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/getmoto/moto/pull/8173?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 94.52%. Comparing base [(`6c68326`)](https://app.codecov.io/gh/getmoto/moto/commit/6c68326479024619214119c6d8835153e5f7804a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) to head [(`47530b5`)](https://app.codecov.io/gh/getmoto/moto/commit/47530b5d6ca0f548be19a88660a3d9f811960354?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).
> Report is 13 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #8173      +/-   ##
==========================================
+ Coverage   94.50%   94.52%   +0.01%     
==========================================
  Files        1150     1150              
  Lines       99203    99359     +156     
==========================================
+ Hits        93752    93915     +163     
+ Misses       5451     5444       -7     
```

| [Flag](https://app.codecov.io/gh/getmoto/moto/pull/8173/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | Coverage Δ | |
|---|---|---|
| [servertests](https://app.codecov.io/gh/getmoto/moto/pull/8173/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `28.76% <33.33%> (-0.04%)` | :arrow_down: |
| [unittests](https://app.codecov.io/gh/getmoto/moto/pull/8173/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `94.49% <100.00%> (+0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/getmoto/moto/pull/8173?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).


Patch:
diff --git a/moto/ec2/models/network_acls.py b/moto/ec2/models/network_acls.py
index aa11829e6..d9570cc53 100644
--- a/moto/ec2/models/network_acls.py
+++ b/moto/ec2/models/network_acls.py
@@ -59,6 +59,7 @@ class NetworkAclBackend:
                 icmp_type=None,
                 port_range_from=None,
                 port_range_to=None,
+                ipv6_cidr_block=None,
             )
 
     def delete_network_acl(self, network_acl_id: str) -> "NetworkAcl":
@@ -87,6 +88,7 @@ class NetworkAclBackend:
         icmp_type: Optional[int],
         port_range_from: Optional[int],
         port_range_to: Optional[int],
+        ipv6_cidr_block: Optional[str],
     ) -> "NetworkAclEntry":
         network_acl = self.get_network_acl(network_acl_id)
         if any(
@@ -96,16 +98,17 @@ class NetworkAclBackend:
             raise NetworkAclEntryAlreadyExistsError(rule_number)
         network_acl_entry = NetworkAclEntry(
             self,
-            network_acl_id,
-            rule_number,
-            protocol,
-            rule_action,
-            egress,
-            cidr_block,
-            icmp_code,
-            icmp_type,
-            port_range_from,
-            port_range_to,
+            network_acl_id=network_acl_id,
+            rule_number=rule_number,
+            protocol=protocol,
+            rule_action=rule_action,
+            egress=egress,
+            cidr_block=cidr_block,
+            icmp_code=icmp_code,
+            icmp_type=icmp_type,
+            port_range_from=port_range_from,
+            port_range_to=port_range_to,
+            ipv6_cidr_block=ipv6_cidr_block,
         )
 
         network_acl.network_acl_entries.append(network_acl_entry)
@@ -136,19 +139,21 @@ class NetworkAclBackend:
         icmp_type: int,
         port_range_from: int,
         port_range_to: int,
+        ipv6_cidr_block: Optional[str],
     ) -> "NetworkAclEntry":
         self.delete_network_acl_entry(network_acl_id, rule_number, egress)
         network_acl_entry = self.create_network_acl_entry(
-            network_acl_id,
-            rule_number,
-            protocol,
-            rule_action,
-            egress,
-            cidr_block,
-            icmp_code,
-            icmp_type,
-            port_range_from,
-            port_range_to,
+            network_acl_id=network_acl_id,
+            rule_number=rule_number,
+            protocol=protocol,
+            rule_action=rule_action,
+            egress=egress,
+            cidr_block=cidr_block,
+            icmp_code=icmp_code,
+            icmp_type=icmp_type,
+            port_range_from=port_range_from,
+            port_range_to=port_range_to,
+            ipv6_cidr_block=ipv6_cidr_block,
         )
         return network_acl_entry
 
@@ -285,6 +290,7 @@ class NetworkAclEntry(TaggedEC2Resource):
         icmp_type: Optional[int],
         port_range_from: Optional[int],
         port_range_to: Optional[int],
+        ipv6_cidr_block: Optional[str],
     ):
         self.ec2_backend = ec2_backend
         self.network_acl_id = network_acl_id
@@ -293,6 +299,7 @@ class NetworkAclEntry(TaggedEC2Resource):
         self.rule_action = rule_action
         self.egress = egress
         self.cidr_block = cidr_block
+        self.ipv6_cidr_block = ipv6_cidr_block
         self.icmp_code = icmp_code
         self.icmp_type = icmp_type
         self.port_range_from = port_range_from
diff --git a/moto/ec2/responses/network_acls.py b/moto/ec2/responses/network_acls.py
index b99b87c35..ed6da1130 100644
--- a/moto/ec2/responses/network_acls.py
+++ b/moto/ec2/responses/network_acls.py
@@ -22,18 +22,20 @@ class NetworkACLs(EC2BaseResponse):
         icmp_type = self._get_param("Icmp.Type")
         port_range_from = self._get_param("PortRange.From")
         port_range_to = self._get_param("PortRange.To")
+        ipv6_cidr_block = self._get_param("Ipv6CidrBlock")
 
         network_acl_entry = self.ec2_backend.create_network_acl_entry(
-            network_acl_id,
-            rule_number,
-            protocol,
-            rule_action,
-            egress,
-            cidr_block,
-            icmp_code,
-            icmp_type,
-            port_range_from,
-            port_range_to,
+            network_acl_id=network_acl_id,
+            rule_number=rule_number,
+            protocol=protocol,
+            rule_action=rule_action,
+            egress=egress,
+            cidr_block=cidr_block,
+            icmp_code=icmp_code,
+            icmp_type=icmp_type,
+            port_range_from=port_range_from,
+            port_range_to=port_range_to,
+            ipv6_cidr_block=ipv6_cidr_block,
         )
 
         template = self.response_template(CREATE_NETWORK_ACL_ENTRY_RESPONSE)
@@ -64,18 +66,20 @@ class NetworkACLs(EC2BaseResponse):
         icmp_type = self._get_param("Icmp.Type")
         port_range_from = self._get_param("PortRange.From")
         port_range_to = self._get_param("PortRange.To")
+        ipv6_cidr_block = self._get_param("Ipv6CidrBlock")
 
         self.ec2_backend.replace_network_acl_entry(
-            network_acl_id,
-            rule_number,
-            protocol,
-            rule_action,
-            egress,
-            cidr_block,
-            icmp_code,
-            icmp_type,
-            port_range_from,
-            port_range_to,
+            network_acl_id=network_acl_id,
+            rule_number=rule_number,
+            protocol=protocol,
+            rule_action=rule_action,
+            egress=egress,
+            cidr_block=cidr_block,
+            icmp_code=icmp_code,
+            icmp_type=icmp_type,
+            port_range_from=port_range_from,
+            port_range_to=port_range_to,
+            ipv6_cidr_block=ipv6_cidr_block,
         )
 
         template = self.response_template(REPLACE_NETWORK_ACL_ENTRY_RESPONSE)
@@ -139,7 +143,12 @@ DESCRIBE_NETWORK_ACL_RESPONSE = """
            <protocol>{{ entry.protocol }}</protocol>
            <ruleAction>{{ entry.rule_action }}</ruleAction>
            <egress>{{ entry.egress.lower() }}</egress>
-           <cidrBlock>{{ entry.cidr_block }}</cidrBlock>
+           {% if entry.cidr_block %}<cidrBlock>{{ entry.cidr_block }}</cidrBlock>{% endif %}
+           {% if entry.ipv6_cidr_block %}<ipv6CidrBlock>{{ entry.ipv6_cidr_block }}</ipv6CidrBlock>{% endif %}
+           {% if entry.icmp_code or entry.icmp_type %}<icmpTypeCode>
+             {% if entry.icmp_code %}<code>{{ entry.icmp_code }}</code>{% endif %}
+             {% if entry.icmp_type %}<type>{{ entry.icmp_type }}</type>{% endif %}
+           </icmpTypeCode>{% endif %}
            {% if entry.port_range_from or entry.port_range_to %}
              <portRange>
                <from>{{ entry.port_range_from }}</from>


Test patch:
diff --git a/.github/workflows/tests_terraform_examples.yml b/.github/workflows/tests_terraform_examples.yml
index 672afce50..d83ef22cc 100644
--- a/.github/workflows/tests_terraform_examples.yml
+++ b/.github/workflows/tests_terraform_examples.yml
@@ -6,12 +6,29 @@ name: Terraform Examples
 on: [workflow_call]
 
 jobs:
+  find-jobs:
+    runs-on: ubuntu-latest
+    name: Find Jobs
+    outputs:
+      folders: ${{ steps.set-folders.outputs.folders }}
+    steps:
+      - uses: actions/checkout@v4
+      - id: set-folders
+        name: Get Services
+        shell: bash
+        run: |
+          cd other_langs/terraform/
+          folders=$(tree -J -d -L 1 | jq -c '.[0].contents | map(.name)')
+          echo $folders
+          echo "folders=$folders" >> $GITHUB_OUTPUT
+
   test:
     runs-on: ubuntu-latest
+    needs: find-jobs
     strategy:
       fail-fast: false
       matrix:
-        service: ["acm", "autoscaling", "awslambda", "cloudfront", "codebuild", "ds", "elb", "iam", "rds", "route53", "sqs", "wafv2"]
+        service: ${{ fromJson(needs.find-jobs.outputs.folders )}}
 
     steps:
     - uses: actions/checkout@v4
@@ -39,31 +56,3 @@ jobs:
         sleep 30
         terraform plan -detailed-exitcode
         terraform apply -destroy --auto-approve
-
-  test_create_only:
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        service: ["ec2"]
-
-    steps:
-    - uses: actions/checkout@v4
-      with:
-        fetch-depth: 0
-    - name: Set up Python 3.8
-      uses: actions/setup-python@v5
-      with:
-        python-version: "3.8"
-    - name: Start MotoServer
-      run: |
-        pip install build
-        python -m build
-        docker run --rm -t --name motoserver -e TEST_SERVER_MODE=true -e AWS_SECRET_ACCESS_KEY=server_secret -e AWS_ACCESS_KEY_ID=server_key -v `pwd`:/moto -p 5000:5000 -v /var/run/docker.sock:/var/run/docker.sock python:3.10-slim /moto/scripts/ci_moto_server.sh &
-        python scripts/ci_wait_for_server.py
-    - name: Run tests
-      run: |
-        mkdir ~/.aws && touch ~/.aws/credentials && echo -e "[default]\naws_access_key_id = test\naws_secret_access_key = test" > ~/.aws/credentials
-        cd other_langs/terraform/${{ matrix.service }}
-        terraform init
-        terraform apply --auto-approve
diff --git a/tests/test_ec2/test_network_acls.py b/tests/test_ec2/test_network_acls.py
index bde8c726c..3fa630763 100644
--- a/tests/test_ec2/test_network_acls.py
+++ b/tests/test_ec2/test_network_acls.py
@@ -69,6 +69,7 @@ def test_network_acl_entries():
         Protocol="6",  # TCP
         RuleAction="ALLOW",
         CidrBlock="0.0.0.0/0",
+        Ipv6CidrBlock="asdf",
         Egress=False,
         PortRange={"From": 443, "To": 443},
     )
@@ -88,6 +89,7 @@ def test_network_acl_entries():
     assert entries[0]["Egress"] is False
     assert entries[0]["PortRange"] == {"To": 443, "From": 443}
     assert entries[0]["CidrBlock"] == "0.0.0.0/0"
+    assert entries[0]["Ipv6CidrBlock"] == "asdf"
 
 
 @mock_aws