Repository: getmoto/moto
Pull request #8142 (2024-09-23 13:21:19)

Add output of VPC subnet tagging to `resourcegroupstaggingapi`
# Motivation

The `resourcegroupstaggingapi` is lacking support for VPC subnets

# Changes

This PR adds VPC subnets to the output of `get_resources`

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/getmoto/moto/pull/8142?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) Report
Attention: Patch coverage is `85.71429%` with `1 line` in your changes missing coverage. Please review.
> Project coverage is 94.49%. Comparing base [(`d8da0ac`)](https://app.codecov.io/gh/getmoto/moto/commit/d8da0ac07690bce3831e886af6f73721fd52f440?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) to head [(`03a1bf5`)](https://app.codecov.io/gh/getmoto/moto/commit/03a1bf54ed4b04622ee04b08d6a355267b1fb8d1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).
> Report is 3 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/getmoto/moto/pull/8142?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | Patch % | Lines |
|---|---|---|
| [moto/resourcegroupstaggingapi/models.py](https://app.codecov.io/gh/getmoto/moto/pull/8142?src=pr&el=tree&filepath=moto%2Fresourcegroupstaggingapi%2Fmodels.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto#diff-bW90by9yZXNvdXJjZWdyb3Vwc3RhZ2dpbmdhcGkvbW9kZWxzLnB5) | 85.71% | [1 Missing :warning: ](https://app.codecov.io/gh/getmoto/moto/pull/8142?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) |

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


```diff
@@            Coverage Diff             @@
##           master    #8142      +/-   ##
==========================================
- Coverage   94.50%   94.49%   -0.01%     
==========================================
  Files        1150     1150              
  Lines       99191    99198       +7     
==========================================
+ Hits        93736    93742       +6     
- Misses       5455     5456       +1     
```

| [Flag](https://app.codecov.io/gh/getmoto/moto/pull/8142/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/8142/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `28.79% <85.71%> (+<0.01%)` | :arrow_up: |
| [unittests](https://app.codecov.io/gh/getmoto/moto/pull/8142/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `94.47% <85.71%> (-0.01%)` | :arrow_down: |

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/8142?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/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py
index f704b8609..b9bad8419 100644
--- a/moto/resourcegroupstaggingapi/models.py
+++ b/moto/resourcegroupstaggingapi/models.py
@@ -663,12 +663,27 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
                     "ResourceARN": f"arn:{self.partition}:ec2:{self.region_name}:{self.account_id}:vpc/{vpc.id}",
                     "Tags": tags,
                 }
+        # VPC Subnet
+        if (
+            not resource_type_filters
+            or "ec2" in resource_type_filters
+            or "ec2:subnet" in resource_type_filters
+        ):
+            for subnet in self.ec2_backend.subnets.values():
+                for subnet_id in subnet.keys():
+                    tags = format_tags(self.ec2_backend.tags.get(subnet_id, {}))
+                    if not tags or not tag_filter(tags):
+                        continue
+                    yield {
+                        "ResourceARN": f"arn:{self.partition}:ec2:{self.region_name}:{self.account_id}:subnet/{subnet_id}",
+                        "Tags": tags,
+                    }
+
         # VPC Customer Gateway
         # VPC DHCP Option Set
         # VPC Internet Gateway
         # VPC Network ACL
         # VPC Route Table
-        # VPC Subnet
         # VPC Virtual Private Gateway
         # VPC VPN Connection
 


Test patch:
diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
index b71734ef2..05e656675 100644
--- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
+++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
@@ -332,20 +332,32 @@ def test_get_resources_ec2():
 def test_get_resources_ec2_vpc():
     ec2 = boto3.resource("ec2", region_name="us-west-2")
     vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
-    ec2.create_tags(Resources=[vpc.id], Tags=[{"Key": "test", "Value": "test"}])
-
-    def assert_response(resp):
-        results = resp.get("ResourceTagMappingList", [])
-        assert len(results) == 1
-        assert vpc.id in results[0]["ResourceARN"]
+    ec2.create_tags(Resources=[vpc.id], Tags=[{"Key": "test", "Value": "test_vpc"}])
+    subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.1.0/24")
+    ec2.create_tags(
+        Resources=[subnet.id], Tags=[{"Key": "test", "Value": "test_subnet"}]
+    )
 
     rtapi = boto3.client("resourcegroupstaggingapi", region_name="us-west-2")
+    # Check that we have one entry for VPC, one for the subnet
     resp = rtapi.get_resources(ResourceTypeFilters=["ec2"])
-    assert_response(resp)
+    assert len(resp["ResourceTagMappingList"]) == 2
+
+    # 1 Entry for VPC
     resp = rtapi.get_resources(ResourceTypeFilters=["ec2:vpc"])
-    assert_response(resp)
-    resp = rtapi.get_resources(TagFilters=[{"Key": "test", "Values": ["test"]}])
-    assert_response(resp)
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert "vpc/" in resp["ResourceTagMappingList"][0]["ResourceARN"]
+    resp = rtapi.get_resources(TagFilters=[{"Key": "test", "Values": ["test_vpc"]}])
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert "vpc/" in resp["ResourceTagMappingList"][0]["ResourceARN"]
+
+    # 1 Entry for Subnet
+    resp = rtapi.get_resources(ResourceTypeFilters=["ec2:subnet"])
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert "subnet/" in resp["ResourceTagMappingList"][0]["ResourceARN"]
+    resp = rtapi.get_resources(TagFilters=[{"Key": "test", "Values": ["test_subnet"]}])
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert "subnet/" in resp["ResourceTagMappingList"][0]["ResourceARN"]
 
 
 @mock_aws