diff --git a/moto/ec2/models.py b/moto/ec2/models.py index a7a34cbf..6666a964 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -3465,19 +3465,30 @@ class SubnetBackend(object): vpc = self.get_vpc( vpc_id ) # Validate VPC exists and the supplied CIDR block is a subnet of the VPC's - vpc_cidr_block = ipaddress.IPv4Network( - six.text_type(vpc.cidr_block), strict=False - ) + vpc_cidr_blocks = [ + ipaddress.IPv4Network( + six.text_type(cidr_block_association["cidr_block"]), strict=False + ) + for cidr_block_association in vpc.get_cidr_block_association_set() + ] try: subnet_cidr_block = ipaddress.IPv4Network( six.text_type(cidr_block), strict=False ) except ValueError: raise InvalidCIDRBlockParameterError(cidr_block) - if not ( - vpc_cidr_block.network_address <= subnet_cidr_block.network_address - and vpc_cidr_block.broadcast_address >= subnet_cidr_block.broadcast_address - ): + + subnet_in_vpc_cidr_range = False + for vpc_cidr_block in vpc_cidr_blocks: + if ( + vpc_cidr_block.network_address <= subnet_cidr_block.network_address + and vpc_cidr_block.broadcast_address + >= subnet_cidr_block.broadcast_address + ): + subnet_in_vpc_cidr_range = True + break + + if not subnet_in_vpc_cidr_range: raise InvalidSubnetRangeError(cidr_block) for subnet in self.get_all_subnets(filters={"vpc-id": vpc_id}): diff --git a/tests/test_ec2/test_subnets.py b/tests/test_ec2/test_subnets.py index 2d30171f..416235f4 100644 --- a/tests/test_ec2/test_subnets.py +++ b/tests/test_ec2/test_subnets.py @@ -417,6 +417,24 @@ def test_create_subnet_with_invalid_cidr_range(): ) +@mock_ec2 +def test_create_subnet_with_invalid_cidr_range_multiple_vpc_cidr_blocks(): + ec2 = boto3.resource("ec2", region_name="us-west-1") + + vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16") + ec2.meta.client.associate_vpc_cidr_block(CidrBlock="10.1.0.0/16", VpcId=vpc.id) + vpc.reload() + vpc.is_default.shouldnt.be.ok + + subnet_cidr_block = "10.2.0.0/20" + with assert_raises(ClientError) as ex: + subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock=subnet_cidr_block) + str(ex.exception).should.equal( + "An error occurred (InvalidSubnet.Range) when calling the CreateSubnet " + "operation: The CIDR '{}' is invalid.".format(subnet_cidr_block) + ) + + @mock_ec2 def test_create_subnet_with_invalid_cidr_block_parameter(): ec2 = boto3.resource("ec2", region_name="us-west-1") @@ -436,6 +454,46 @@ def test_create_subnet_with_invalid_cidr_block_parameter(): ) +@mock_ec2 +def test_create_subnets_with_multiple_vpc_cidr_blocks(): + 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.meta.client.associate_vpc_cidr_block(CidrBlock="10.1.0.0/16", VpcId=vpc.id) + vpc.reload() + vpc.is_default.shouldnt.be.ok + + subnet_cidr_block_primary = "10.0.0.0/24" + subnet_primary = ec2.create_subnet( + VpcId=vpc.id, CidrBlock=subnet_cidr_block_primary + ) + + subnet_cidr_block_secondary = "10.1.0.0/24" + subnet_secondary = ec2.create_subnet( + VpcId=vpc.id, CidrBlock=subnet_cidr_block_secondary + ) + + subnets = client.describe_subnets( + SubnetIds=[subnet_primary.id, subnet_secondary.id] + )["Subnets"] + subnets.should.have.length_of(2) + + for subnet in subnets: + subnet.should.have.key("AvailabilityZone") + subnet.should.have.key("AvailabilityZoneId") + subnet.should.have.key("AvailableIpAddressCount") + subnet.should.have.key("CidrBlock") + subnet.should.have.key("State") + subnet.should.have.key("SubnetId") + subnet.should.have.key("VpcId") + subnet.shouldnt.have.key("Tags") + subnet.should.have.key("DefaultForAz").which.should.equal(False) + subnet.should.have.key("MapPublicIpOnLaunch").which.should.equal(False) + subnet.should.have.key("OwnerId") + subnet.should.have.key("AssignIpv6AddressOnCreation").which.should.equal(False) + + @mock_ec2 def test_create_subnets_with_overlapping_cidr_blocks(): ec2 = boto3.resource("ec2", region_name="us-west-1")