Merge pull request #615 from yannlambret/enhance-vpc-support
Add support for VPC attributes management, and fix a bug about the de…
This commit is contained in:
commit
e37094e2ab
@ -1750,7 +1750,11 @@ class VPC(TaggedEC2Resource):
|
||||
self.cidr_block = cidr_block
|
||||
self.dhcp_options = None
|
||||
self.state = 'available'
|
||||
self.is_default = is_default
|
||||
self.is_default = 'true' if is_default else 'false'
|
||||
self.enable_dns_support = 'true'
|
||||
# This attribute is set to 'true' only for default VPCs
|
||||
# or VPCs created using the wizard of the VPC console
|
||||
self.enable_dns_hostnames = 'true' if is_default else 'false'
|
||||
|
||||
@classmethod
|
||||
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
|
||||
@ -1847,6 +1851,20 @@ class VPCBackend(object):
|
||||
vpc.dhcp_options = None
|
||||
return vpc
|
||||
|
||||
def describe_vpc_attribute(self, vpc_id, attr_name):
|
||||
vpc = self.get_vpc(vpc_id)
|
||||
if attr_name in ('enable_dns_support', 'enable_dns_hostnames'):
|
||||
return getattr(vpc, attr_name)
|
||||
else:
|
||||
raise InvalidParameterValueError(attr_name)
|
||||
|
||||
def modify_vpc_attribute(self, vpc_id, attr_name, attr_value):
|
||||
vpc = self.get_vpc(vpc_id)
|
||||
if attr_name in ('enable_dns_support', 'enable_dns_hostnames'):
|
||||
setattr(vpc, attr_name, attr_value)
|
||||
else:
|
||||
raise InvalidParameterValueError(attr_name)
|
||||
|
||||
|
||||
class VPCPeeringConnectionStatus(object):
|
||||
def __init__(self, code='initiating-request', message=''):
|
||||
@ -1936,14 +1954,14 @@ class VPCPeeringConnectionBackend(object):
|
||||
|
||||
|
||||
class Subnet(TaggedEC2Resource):
|
||||
def __init__(self, ec2_backend, subnet_id, vpc_id, cidr_block, availability_zone, defaultForAz,
|
||||
def __init__(self, ec2_backend, subnet_id, vpc_id, cidr_block, availability_zone, default_for_az,
|
||||
map_public_ip_on_launch):
|
||||
self.ec2_backend = ec2_backend
|
||||
self.id = subnet_id
|
||||
self.vpc_id = vpc_id
|
||||
self.cidr_block = cidr_block
|
||||
self._availability_zone = availability_zone
|
||||
self.defaultForAz = defaultForAz
|
||||
self.default_for_az = default_for_az
|
||||
self.map_public_ip_on_launch = map_public_ip_on_launch
|
||||
|
||||
@classmethod
|
||||
@ -1996,7 +2014,7 @@ class Subnet(TaggedEC2Resource):
|
||||
|
||||
Taken from: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html
|
||||
"""
|
||||
if filter_name in ['cidr', 'cidrBlock', 'cidr-block']:
|
||||
if filter_name in ('cidr', 'cidrBlock', 'cidr-block'):
|
||||
return self.cidr_block
|
||||
elif filter_name == 'vpc-id':
|
||||
return self.vpc_id
|
||||
@ -2004,8 +2022,8 @@ class Subnet(TaggedEC2Resource):
|
||||
return self.id
|
||||
elif filter_name == 'availabilityZone':
|
||||
return self.availability_zone
|
||||
elif filter_name == 'defaultForAz':
|
||||
return self.defaultForAz
|
||||
elif filter_name in ('defaultForAz', 'default-for-az'):
|
||||
return self.default_for_az
|
||||
|
||||
filter_value = super(Subnet, self).get_filter_value(filter_name)
|
||||
|
||||
@ -2035,9 +2053,9 @@ class SubnetBackend(object):
|
||||
def create_subnet(self, vpc_id, cidr_block, availability_zone=None):
|
||||
subnet_id = random_subnet_id()
|
||||
vpc = self.get_vpc(vpc_id) # Validate VPC exists
|
||||
defaultForAz = "true" if vpc.is_default else "false"
|
||||
map_public_ip_on_launch = "true" if vpc.is_default else "false"
|
||||
subnet = Subnet(self, subnet_id, vpc_id, cidr_block, availability_zone, defaultForAz, map_public_ip_on_launch)
|
||||
default_for_az = vpc.is_default
|
||||
map_public_ip_on_launch = vpc.is_default
|
||||
subnet = Subnet(self, subnet_id, vpc_id, cidr_block, availability_zone, default_for_az, map_public_ip_on_launch)
|
||||
|
||||
# AWS associates a new subnet with the default Network ACL
|
||||
self.associate_default_network_acl_with_subnet(subnet_id)
|
||||
|
@ -79,7 +79,7 @@ DESCRIBE_SUBNETS_RESPONSE = """
|
||||
<cidrBlock>{{ subnet.cidr_block }}</cidrBlock>
|
||||
<availableIpAddressCount>251</availableIpAddressCount>
|
||||
<availabilityZone>{{ subnet.availability_zone }}</availabilityZone>
|
||||
<defaultForAz>{{ subnet.defaultForAz }}</defaultForAz>
|
||||
<defaultForAz>{{ subnet.default_for_az }}</defaultForAz>
|
||||
<mapPublicIpOnLaunch>{{ subnet.map_public_ip_on_launch }}</mapPublicIpOnLaunch>
|
||||
<tagSet>
|
||||
{% for tag in subnet.get_tags() %}
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from moto.core.responses import BaseResponse
|
||||
from moto.core.utils import camelcase_to_underscores
|
||||
from moto.ec2.utils import filters_from_querystring, vpc_ids_from_querystring
|
||||
|
||||
|
||||
@ -23,6 +24,24 @@ class VPCs(BaseResponse):
|
||||
template = self.response_template(DESCRIBE_VPCS_RESPONSE)
|
||||
return template.render(vpcs=vpcs)
|
||||
|
||||
def describe_vpc_attribute(self):
|
||||
vpc_id = self.querystring.get('VpcId')[0]
|
||||
attribute = self.querystring.get('Attribute')[0]
|
||||
attr_name = camelcase_to_underscores(attribute)
|
||||
value = self.ec2_backend.describe_vpc_attribute(vpc_id, attr_name)
|
||||
template = self.response_template(DESCRIBE_VPC_ATTRIBUTE_RESPONSE)
|
||||
return template.render(vpc_id=vpc_id, attribute=attribute, value=value)
|
||||
|
||||
def modify_vpc_attribute(self):
|
||||
vpc_id = self.querystring.get('VpcId')[0]
|
||||
|
||||
for attribute in ('EnableDnsSupport', 'EnableDnsHostnames'):
|
||||
if self.querystring.get('%s.Value' % attribute):
|
||||
attr_name = camelcase_to_underscores(attribute)
|
||||
attr_value = self.querystring.get('%s.Value' % attribute)[0]
|
||||
self.ec2_backend.modify_vpc_attribute(vpc_id, attr_name, attr_value)
|
||||
return MODIFY_VPC_ATTRIBUTE_RESPONSE
|
||||
|
||||
|
||||
CREATE_VPC_RESPONSE = """
|
||||
<CreateVpcResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
@ -79,3 +98,18 @@ DELETE_VPC_RESPONSE = """
|
||||
<return>true</return>
|
||||
</DeleteVpcResponse>
|
||||
"""
|
||||
|
||||
DESCRIBE_VPC_ATTRIBUTE_RESPONSE = """
|
||||
<DescribeVpcAttributeResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
|
||||
<vpcId>{{ vpc_id }}</vpcId>
|
||||
<{{ attribute }}>
|
||||
<value>{{ value }}</value>
|
||||
</{{ attribute }}>
|
||||
</DescribeVpcAttributeResponse>"""
|
||||
|
||||
MODIFY_VPC_ATTRIBUTE_RESPONSE = """
|
||||
<ModifyVpcAttributeResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
|
||||
<return>true</return>
|
||||
</ModifyVpcAttributeResponse>"""
|
||||
|
@ -71,19 +71,59 @@ def test_subnet_should_have_proper_availability_zone_set():
|
||||
subnetA = conn.create_subnet(vpcA.id, "10.0.0.0/24", availability_zone='us-west-1b')
|
||||
subnetA.availability_zone.should.equal('us-west-1b')
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_default_subnet():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
default_vpc = ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
default_vpc.reload()
|
||||
default_vpc.is_default.should.be.ok
|
||||
|
||||
subnet = ec2.create_subnet(VpcId=default_vpc.id, CidrBlock='172.31.0.0/20', AvailabilityZone='us-west-1a')
|
||||
subnet.reload()
|
||||
subnet.map_public_ip_on_launch.should.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_non_default_subnet():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
|
||||
# Create the non default VPC
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
vpc.reload()
|
||||
vpc.is_default.shouldnt.be.ok
|
||||
|
||||
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-1a')
|
||||
subnet.reload()
|
||||
subnet.map_public_ip_on_launch.shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_modify_subnet_attribute():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-1a')
|
||||
|
||||
subnet.map_public_ip_on_launch.should.be.false
|
||||
# 'map_public_ip_on_launch' is set when calling 'DescribeSubnets' action
|
||||
subnet.reload()
|
||||
|
||||
# For non default subnet, attribute value should be 'False'
|
||||
subnet.map_public_ip_on_launch.shouldnt.be.ok
|
||||
|
||||
client.modify_subnet_attribute(SubnetId=subnet.id, MapPublicIpOnLaunch={'Value': True})
|
||||
subnet.reload()
|
||||
|
||||
subnet.map_public_ip_on_launch.should.be.true
|
||||
subnet.map_public_ip_on_launch.should.be.ok
|
||||
|
||||
@mock_ec2
|
||||
def test_modify_subnet_attribute_validation():
|
||||
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
||||
import tests.backport_assert_raises # flake8: noqa
|
||||
from nose.tools import assert_raises
|
||||
|
||||
import boto3
|
||||
import boto
|
||||
from boto.exception import EC2ResponseError
|
||||
import sure # noqa
|
||||
@ -208,3 +209,86 @@ def test_vpc_get_by_tag_value_subset():
|
||||
vpc_ids = tuple(map(lambda v: v.id, vpcs))
|
||||
vpc1.id.should.be.within(vpc_ids)
|
||||
vpc2.id.should.be.within(vpc_ids)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_default_vpc():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
default_vpc = ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
default_vpc.reload()
|
||||
default_vpc.is_default.should.be.ok
|
||||
|
||||
# Test default values for VPC attributes
|
||||
response = default_vpc.describe_attribute(Attribute='enableDnsSupport')
|
||||
attr = response.get('EnableDnsSupport')
|
||||
attr.get('Value').should.be.ok
|
||||
|
||||
response = default_vpc.describe_attribute(Attribute='enableDnsHostnames')
|
||||
attr = response.get('EnableDnsHostnames')
|
||||
attr.get('Value').should.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_non_default_vpc():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
|
||||
# Create the non default VPC
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
vpc.reload()
|
||||
vpc.is_default.shouldnt.be.ok
|
||||
|
||||
# Test default values for VPC attributes
|
||||
response = vpc.describe_attribute(Attribute='enableDnsSupport')
|
||||
attr = response.get('EnableDnsSupport')
|
||||
attr.get('Value').should.be.ok
|
||||
|
||||
response = vpc.describe_attribute(Attribute='enableDnsHostnames')
|
||||
attr = response.get('EnableDnsHostnames')
|
||||
attr.get('Value').shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_vpc_modify_enable_dns_support():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
|
||||
# Test default values for VPC attributes
|
||||
response = vpc.describe_attribute(Attribute='enableDnsSupport')
|
||||
attr = response.get('EnableDnsSupport')
|
||||
attr.get('Value').should.be.ok
|
||||
|
||||
vpc.modify_attribute(EnableDnsSupport={'Value': False})
|
||||
|
||||
response = vpc.describe_attribute(Attribute='enableDnsSupport')
|
||||
attr = response.get('EnableDnsSupport')
|
||||
attr.get('Value').shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_vpc_modify_enable_dns_hostnames():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
||||
# Create the default VPC
|
||||
ec2.create_vpc(CidrBlock='172.31.0.0/16')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
|
||||
# Test default values for VPC attributes
|
||||
response = vpc.describe_attribute(Attribute='enableDnsHostnames')
|
||||
attr = response.get('EnableDnsHostnames')
|
||||
attr.get('Value').shouldnt.be.ok
|
||||
|
||||
vpc.modify_attribute(EnableDnsHostnames={'Value': True})
|
||||
|
||||
response = vpc.describe_attribute(Attribute='enableDnsHostnames')
|
||||
attr = response.get('EnableDnsHostnames')
|
||||
attr.get('Value').should.be.ok
|
||||
|
Loading…
Reference in New Issue
Block a user