Repository: getmoto/moto

Issue:
The filter 'vpcId' for DescribeSubnets has not been implemented in Moto yet.
Any chances of adding this in the near future?


Discussion:
Also getting `The filter 'state' for DescribeSubnets has not been implemented in Moto yet.`.
This is not a feature I currently need, but pull requests welcome if someone else has time to implement.
I can perhaps give it a try. Can you give a pointer what file to start with?
Awesome.

[This](https://github.com/spulec/moto/blob/master/moto/ec2/utils.py) should be the main file that will need changing. Look at the `filters_from_querystring` function and the `EC2_RESOURCE_TO_PREFIX` constant.

You should be able to add a new test [here](https://github.com/spulec/moto/blob/master/tests/test_ec2/test_subnets.py) to verify any changes.

Resolving patch:
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -3307,6 +3307,7 @@ def __init__(
         ]  # Reserved by AWS
         self._unused_ips = set()  # if instance is destroyed hold IP here for reuse
         self._subnet_ips = {}  # has IP: instance
+        self.state = "available"
 
     @staticmethod
     def cloudformation_name_type():
@@ -3387,6 +3388,8 @@ def get_filter_value(self, filter_name):
             return self.availability_zone
         elif filter_name in ("defaultForAz", "default-for-az"):
             return self.default_for_az
+        elif filter_name == "state":
+            return self.state
         else:
             return super(Subnet, self).get_filter_value(filter_name, "DescribeSubnets")
 
diff --git a/moto/ec2/responses/subnets.py b/moto/ec2/responses/subnets.py
--- a/moto/ec2/responses/subnets.py
+++ b/moto/ec2/responses/subnets.py
@@ -99,7 +99,7 @@ def modify_subnet_attribute(self):
     {% for subnet in subnets %}
       <item>
         <subnetId>{{ subnet.id }}</subnetId>
-        <state>available</state>
+        <state>{{ subnet.state }}</state>
         <vpcId>{{ subnet.vpc_id }}</vpcId>
         <cidrBlock>{{ subnet.cidr_block }}</cidrBlock>
         <availableIpAddressCount>{{ subnet.available_ip_addresses }}</availableIpAddressCount>


Test patch:
diff --git a/tests/test_ec2/test_subnets.py b/tests/test_ec2/test_subnets.py
--- a/tests/test_ec2/test_subnets.py
+++ b/tests/test_ec2/test_subnets.py
@@ -678,3 +678,59 @@ def test_run_instances_should_attach_to_default_subnet():
         subnets[0]["AvailableIpAddressCount"] == 4090
         or subnets[1]["AvailableIpAddressCount"] == 4090
     )
+
+
+@mock_ec2
+def test_describe_subnets_by_vpc_id():
+    ec2 = boto3.resource("ec2", region_name="us-west-1")
+    client = boto3.client("ec2", region_name="us-west-1")
+
+    vpc1 = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+    subnet1 = ec2.create_subnet(
+        VpcId=vpc1.id, CidrBlock="10.0.0.0/24", AvailabilityZone="us-west-1a"
+    )
+    vpc2 = ec2.create_vpc(CidrBlock="172.31.0.0/16")
+    subnet2 = ec2.create_subnet(
+        VpcId=vpc2.id, CidrBlock="172.31.48.0/20", AvailabilityZone="us-west-1b"
+    )
+
+    subnets = client.describe_subnets(
+        Filters=[{"Name": "vpc-id", "Values": [vpc1.id]}]
+    ).get("Subnets", [])
+    subnets.should.have.length_of(1)
+    subnets[0]["SubnetId"].should.equal(subnet1.id)
+
+    subnets = client.describe_subnets(
+        Filters=[{"Name": "vpc-id", "Values": [vpc2.id]}]
+    ).get("Subnets", [])
+    subnets.should.have.length_of(1)
+    subnets[0]["SubnetId"].should.equal(subnet2.id)
+
+    # Specify multiple VPCs in Filter.
+    subnets = client.describe_subnets(
+        Filters=[{"Name": "vpc-id", "Values": [vpc1.id, vpc2.id]}]
+    ).get("Subnets", [])
+    subnets.should.have.length_of(2)
+
+    # Specify mismatched SubnetIds/Filters.
+    subnets = client.describe_subnets(
+        SubnetIds=[subnet1.id], Filters=[{"Name": "vpc-id", "Values": [vpc2.id]}]
+    ).get("Subnets", [])
+    subnets.should.have.length_of(0)
+
+
+@mock_ec2
+def test_describe_subnets_by_state():
+    ec2 = boto3.resource("ec2", region_name="us-west-1")
+    client = boto3.client("ec2", region_name="us-west-1")
+
+    vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+    ec2.create_subnet(
+        VpcId=vpc.id, CidrBlock="10.0.0.0/24", AvailabilityZone="us-west-1a"
+    )
+
+    subnets = client.describe_subnets(
+        Filters=[{"Name": "state", "Values": ["available"]}]
+    ).get("Subnets", [])
+    for subnet in subnets:
+        subnet["State"].should.equal("available")