diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 25f32bc76..3549c29fe 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -1695,11 +1695,12 @@ class VPCPeeringConnectionBackend(object): class Subnet(TaggedEC2Resource): - def __init__(self, ec2_backend, subnet_id, vpc_id, cidr_block): + def __init__(self, ec2_backend, subnet_id, vpc_id, cidr_block, availability_zone): self.ec2_backend = ec2_backend self.id = subnet_id self.vpc_id = vpc_id self.cidr_block = cidr_block + self._availability_zone = availability_zone @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name): @@ -1715,21 +1716,42 @@ class Subnet(TaggedEC2Resource): @property def availability_zone(self): - # This could probably be smarter, but there doesn't appear to be a - # way to pull AZs for a region in boto - return self.ec2_backend.region_name + "a" + if self._availability_zone is None: + # This could probably be smarter, but there doesn't appear to be a + # way to pull AZs for a region in boto + return self.ec2_backend.region_name + "a" + else: + return self._availability_zone @property def physical_resource_id(self): return self.id def get_filter_value(self, filter_name): + """ + API Version 2014-10-01 defines the following filters for DescribeSubnets: + + * availabilityZone + * available-ip-address-count + * cidrBlock + * defaultForAz + * state + * subnet-id + * tag:key=value + * tag-key + * tag-value + * vpc-id + + Taken from: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html + """ if filter_name in ['cidr', 'cidrBlock', 'cidr-block']: return self.cidr_block elif filter_name == 'vpc-id': return self.vpc_id elif filter_name == 'subnet-id': return self.id + elif filter_name == 'availabilityZone': + return self.availability_zone filter_value = super(Subnet, self).get_filter_value(filter_name) @@ -1756,9 +1778,9 @@ class SubnetBackend(object): raise InvalidSubnetIdError(subnet_id) return subnet - def create_subnet(self, vpc_id, cidr_block): + def create_subnet(self, vpc_id, cidr_block, availability_zone=None): subnet_id = random_subnet_id() - subnet = Subnet(self, subnet_id, vpc_id, cidr_block) + subnet = Subnet(self, subnet_id, vpc_id, cidr_block, availability_zone) self.get_vpc(vpc_id) # Validate VPC exists # AWS associates a new subnet with the default Network ACL diff --git a/moto/ec2/responses/subnets.py b/moto/ec2/responses/subnets.py index 9f0808648..f0cd6db33 100644 --- a/moto/ec2/responses/subnets.py +++ b/moto/ec2/responses/subnets.py @@ -7,7 +7,15 @@ class Subnets(BaseResponse): def create_subnet(self): vpc_id = self.querystring.get('VpcId')[0] cidr_block = self.querystring.get('CidrBlock')[0] - subnet = self.ec2_backend.create_subnet(vpc_id, cidr_block) + if 'AvailabilityZone' in self.querystring: + availability_zone = self.querystring['AvailabilityZone'][0] + else: + availability_zone = None + subnet = self.ec2_backend.create_subnet( + vpc_id, + cidr_block, + availability_zone, + ) template = self.response_template(CREATE_SUBNET_RESPONSE) return template.render(subnet=subnet) diff --git a/tests/test_ec2/test_subnets.py b/tests/test_ec2/test_subnets.py index c26267405..e148eac61 100644 --- a/tests/test_ec2/test_subnets.py +++ b/tests/test_ec2/test_subnets.py @@ -4,6 +4,7 @@ import tests.backport_assert_raises from nose.tools import assert_raises import boto +import boto.vpc from boto.exception import EC2ResponseError import sure # noqa @@ -62,12 +63,12 @@ def test_subnet_tagging(): @mock_ec2 def test_get_subnets_filtering(): - conn = boto.connect_vpc('the_key', 'the_secret') + conn = boto.vpc.connect_to_region('us-west-1') vpcA = conn.create_vpc("10.0.0.0/16") - subnetA = conn.create_subnet(vpcA.id, "10.0.0.0/24") + subnetA = conn.create_subnet(vpcA.id, "10.0.0.0/24", availability_zone='us-west-1a') vpcB = conn.create_vpc("10.0.0.0/16") - subnetB1 = conn.create_subnet(vpcB.id, "10.0.0.0/24") - subnetB2 = conn.create_subnet(vpcB.id, "10.0.1.0/24") + subnetB1 = conn.create_subnet(vpcB.id, "10.0.0.0/24", availability_zone='us-west-1a') + subnetB2 = conn.create_subnet(vpcB.id, "10.0.1.0/24", availability_zone='us-west-1b') all_subnets = conn.get_all_subnets() all_subnets.should.have.length_of(3) @@ -100,5 +101,10 @@ def test_get_subnets_filtering(): subnets_by_id.should.have.length_of(1) set([subnet.id for subnet in subnets_by_id]).should.equal(set([subnetA.id])) + # Filter by availabilityZone + subnets_by_az = conn.get_all_subnets(filters={'availabilityZone': 'us-west-1a', 'vpc-id': vpcB.id}) + subnets_by_az.should.have.length_of(1) + set([subnet.id for subnet in subnets_by_az]).should.equal(set([subnetB1.id])) + # Unsupported filter conn.get_all_subnets.when.called_with(filters={'not-implemented-filter': 'foobar'}).should.throw(NotImplementedError)