Repository: getmoto/moto

Issue:
VPN Gateway filters not implemented
Filters for VPN Gateway aren't implemented, specifically attachment.vpc-id. This can be reproduced via this code:

```python
    ec2 = boto3.client("ec2", region_name="us-east-1")

    vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
    vpc_id = vpc["Vpc"]["VpcId"]
    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]

    ec2.attach_vpn_gateway(VpcId=vpc_id, VpnGatewayId=gateway_id)

    gateways = ec2.describe_vpn_gateways(
        Filters=[{"Name": "attachment.vpc-id", "Values": [vpc_id]}]
    )
```

You would expect gateways to return a list of length 1, with the VPN gateway attached. Instead you receive:
```
moto.ec2.exceptions.FilterNotImplementedError: The filter 'attachment.vpc-id' for DescribeVpnGateways has not been implemented in Moto yet. Feel free to open an issue at https://github.com/spulec/moto/issues
```

This was tested with the current mainline branch, and I'll be adding a PR for this, `attachment.state`, `vpn-gateway-id` and `type` filters.  I found this originally while trying to attach a VPN gateway to a VPC via terraform in localstack - terraform searches for VPN gateways via `attachment.vpc-id`. 

There are other unimplemented filters - `amazon-side-asn`, `availability-zone`, but it doesn't appear that moto is storing those values anywhere for a VPN gateway.


Discussion:

Resolving patch:
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -4973,6 +4973,14 @@ def __init__(self, ec2_backend, id, type):
         super(VpnGateway, self).__init__()
 
     def get_filter_value(self, filter_name):
+        if filter_name == "attachment.vpc-id":
+            return self.attachments.keys()
+        elif filter_name == "attachment.state":
+            return [attachment.state for attachment in self.attachments.values()]
+        elif filter_name == "vpn-gateway-id":
+            return self.id
+        elif filter_name == "type":
+            return self.type
         return super(VpnGateway, self).get_filter_value(
             filter_name, "DescribeVpnGateways"
         )


Test patch:
diff --git a/tests/test_ec2/test_virtual_private_gateways.py b/tests/test_ec2/test_virtual_private_gateways.py
--- a/tests/test_ec2/test_virtual_private_gateways.py
+++ b/tests/test_ec2/test_virtual_private_gateways.py
@@ -1,8 +1,9 @@
 from __future__ import unicode_literals
 import boto
+import boto3
 import sure  # noqa
 
-from moto import mock_ec2_deprecated
+from moto import mock_ec2_deprecated, mock_ec2
 
 
 @mock_ec2_deprecated
@@ -33,6 +34,138 @@ def test_describe_vpn_gateway():
     vpn_gateway.availability_zone.should.equal("us-east-1a")
 
 
+@mock_ec2
+def test_describe_vpn_connections_attachment_vpc_id_filter():
+    """ describe_vpn_gateways attachment.vpc-id filter """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+    vpc_id = vpc["Vpc"]["VpcId"]
+    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]
+
+    ec2.attach_vpn_gateway(VpcId=vpc_id, VpnGatewayId=gateway_id)
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "attachment.vpc-id", "Values": [vpc_id]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(1)
+    gateways["VpnGateways"][0]["VpnGatewayId"].should.equal(gateway_id)
+    gateways["VpnGateways"][0]["VpcAttachments"].should.contain(
+        {"State": "attached", "VpcId": vpc_id}
+    )
+
+
+@mock_ec2
+def test_describe_vpn_connections_state_filter_attached():
+    """ describe_vpn_gateways attachment.state filter - match attached """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+    vpc_id = vpc["Vpc"]["VpcId"]
+    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]
+
+    ec2.attach_vpn_gateway(VpcId=vpc_id, VpnGatewayId=gateway_id)
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "attachment.state", "Values": ["attached"]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(1)
+    gateways["VpnGateways"][0]["VpnGatewayId"].should.equal(gateway_id)
+    gateways["VpnGateways"][0]["VpcAttachments"].should.contain(
+        {"State": "attached", "VpcId": vpc_id}
+    )
+
+
+@mock_ec2
+def test_describe_vpn_connections_state_filter_deatched():
+    """ describe_vpn_gateways attachment.state filter - don't match detatched """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+    vpc_id = vpc["Vpc"]["VpcId"]
+    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]
+
+    ec2.attach_vpn_gateway(VpcId=vpc_id, VpnGatewayId=gateway_id)
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "attachment.state", "Values": ["detached"]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(0)
+
+
+@mock_ec2
+def test_describe_vpn_connections_id_filter_match():
+    """ describe_vpn_gateways vpn-gateway-id filter - match correct id """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "vpn-gateway-id", "Values": [gateway_id]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(1)
+    gateways["VpnGateways"][0]["VpnGatewayId"].should.equal(gateway_id)
+
+
+@mock_ec2
+def test_describe_vpn_connections_id_filter_miss():
+    """ describe_vpn_gateways vpn-gateway-id filter - don't match """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "vpn-gateway-id", "Values": ["unknown_gateway_id"]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(0)
+
+
+@mock_ec2
+def test_describe_vpn_connections_type_filter_match():
+    """ describe_vpn_gateways type filter - match """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    gateway = ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+    gateway_id = gateway["VpnGateway"]["VpnGatewayId"]
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "type", "Values": ["ipsec.1"]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(1)
+    gateways["VpnGateways"][0]["VpnGatewayId"].should.equal(gateway_id)
+
+
+@mock_ec2
+def test_describe_vpn_connections_type_filter_miss():
+    """ describe_vpn_gateways type filter - don't match """
+
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    ec2.create_vpn_gateway(AvailabilityZone="us-east-1a", Type="ipsec.1")
+
+    gateways = ec2.describe_vpn_gateways(
+        Filters=[{"Name": "type", "Values": ["unknown_type"]}]
+    )
+
+    gateways["VpnGateways"].should.have.length_of(0)
+
+
 @mock_ec2_deprecated
 def test_vpn_gateway_vpc_attachment():
     conn = boto.connect_vpc("the_key", "the_secret")