Virtual Private Gateway functionality

This commit is contained in:
Tyler Sanders 2014-12-02 10:28:09 -06:00
parent 1a015d0e39
commit 166fd69515
5 changed files with 231 additions and 9 deletions

View File

@ -80,6 +80,14 @@ class InvalidNetworkAclIdError(EC2ClientError):
.format(network_acl_id)) .format(network_acl_id))
class InvalidVpnGatewayIdError(EC2ClientError):
def __init__(self, network_acl_id):
super(InvalidVpnGatewayIdError, self).__init__(
"InvalidVpnGatewayID.NotFound",
"The virtual private gateway ID '{0}' does not exist"
.format(network_acl_id))
class InvalidNetworkInterfaceIdError(EC2ClientError): class InvalidNetworkInterfaceIdError(EC2ClientError):
def __init__(self, eni_id): def __init__(self, eni_id):
super(InvalidNetworkInterfaceIdError, self).__init__( super(InvalidNetworkInterfaceIdError, self).__init__(

View File

@ -53,7 +53,8 @@ from .exceptions import (
TagLimitExceeded, TagLimitExceeded,
InvalidID, InvalidID,
InvalidCIDRSubnetError, InvalidCIDRSubnetError,
InvalidNetworkAclIdError InvalidNetworkAclIdError,
InvalidVpnGatewayIdError
) )
from .utils import ( from .utils import (
EC2_RESOURCE_TO_PREFIX, EC2_RESOURCE_TO_PREFIX,
@ -89,7 +90,8 @@ from .utils import (
filter_internet_gateways, filter_internet_gateways,
filter_reservations, filter_reservations,
random_network_acl_id, random_network_acl_id,
random_network_acl_subnet_association_id) random_network_acl_subnet_association_id,
random_vpn_gateway_id)
def validate_resource_ids(resource_ids): def validate_resource_ids(resource_ids):
@ -2442,6 +2444,57 @@ class NetworkAclEntry(TaggedEC2Resource):
self.port_range_to = port_range_to self.port_range_to = port_range_to
class VpnGateway(TaggedEC2Resource):
def __init__(self, ec2_backend, id, type):
self.ec2_backend = ec2_backend
self.id = id
self.type = type
self.attachments = {}
super(VpnGateway, self).__init__()
class VpnGatewayAttachment(object):
def __init__(self, vpc_id, state):
self.vpc_id = vpc_id
self.state = state
super(VpnGatewayAttachment, self).__init__()
class VpnGatewayBackend(object):
def __init__(self):
self.vpn_gateways = {}
super(VpnGatewayBackend, self).__init__()
def create_vpn_gateway(self, type='ipsec.1'):
vpn_gateway_id = random_vpn_gateway_id()
vpn_gateway = VpnGateway(self, vpn_gateway_id, type)
self.vpn_gateways[vpn_gateway_id] = vpn_gateway
return vpn_gateway
def get_all_vpn_gateways(self, filters=None):
vpn_gateways = self.vpn_gateways.values()
return generic_filter(filters, vpn_gateways)
def get_vpn_gateway(self, vpn_gateway_id):
vpn_gateway = self.vpn_gateways.get(vpn_gateway_id, None)
if not vpn_gateway:
raise InvalidVpnGatewayIdError(vpn_gateway_id)
return vpn_gateway
def attach_vpn_gateway(self, vpn_gateway_id, vpc_id):
vpn_gateway = self.get_vpn_gateway(vpn_gateway_id)
self.get_vpc(vpc_id)
attachment = VpnGatewayAttachment(vpc_id, state='attached')
vpn_gateway.attachments[vpc_id] = attachment
return attachment
def delete_vpn_gateway(self, vpn_gateway_id):
deleted = self.vpn_gateways.pop(vpn_gateway_id, None)
if not deleted:
raise InvalidVpnGatewayIdError(vpn_gateway_id)
return deleted
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend, class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend, RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend,
VPCBackend, SubnetBackend, SubnetRouteTableAssociationBackend, VPCBackend, SubnetBackend, SubnetRouteTableAssociationBackend,
@ -2450,7 +2503,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RouteTableBackend, RouteBackend, InternetGatewayBackend, RouteTableBackend, RouteBackend, InternetGatewayBackend,
VPCGatewayAttachmentBackend, SpotRequestBackend, VPCGatewayAttachmentBackend, SpotRequestBackend,
ElasticAddressBackend, KeyPairBackend, DHCPOptionsSetBackend, ElasticAddressBackend, KeyPairBackend, DHCPOptionsSetBackend,
NetworkAclBackend): NetworkAclBackend, VpnGatewayBackend):
def __init__(self, region_name): def __init__(self, region_name):
super(EC2Backend, self).__init__() super(EC2Backend, self).__init__()
@ -2509,7 +2562,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-connection']: elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-connection']:
self.raise_not_implemented_error('DescribeVpnConnections') self.raise_not_implemented_error('DescribeVpnConnections')
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-gateway']: elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-gateway']:
self.raise_not_implemented_error('DescribeVpnGateways') self.get_vpn_gateway(vpn_gateway_id=resource_id)
return True return True
ec2_backends = {} ec2_backends = {}

View File

@ -1,19 +1,110 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from jinja2 import Template
from moto.core.responses import BaseResponse from moto.core.responses import BaseResponse
from moto.ec2.utils import filters_from_querystring
class VirtualPrivateGateways(BaseResponse): class VirtualPrivateGateways(BaseResponse):
def attach_vpn_gateway(self): def attach_vpn_gateway(self):
raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).attach_vpn_gateway is not yet implemented') vpn_gateway_id = self.querystring.get('VpnGatewayId')[0]
vpc_id = self.querystring.get('VpcId')[0]
attachment = self.ec2_backend.attach_vpn_gateway(
vpn_gateway_id,
vpc_id
)
template = Template(ATTACH_VPN_GATEWAY_RESPONSE)
return template.render(attachment=attachment)
def create_vpn_gateway(self): def create_vpn_gateway(self):
raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).create_vpn_gateway is not yet implemented') type = self.querystring.get('Type', None)[0]
vpn_gateway = self.ec2_backend.create_vpn_gateway(type)
template = Template(CREATE_VPN_GATEWAY_RESPONSE)
return template.render(vpn_gateway=vpn_gateway)
def delete_vpn_gateway(self): def delete_vpn_gateway(self):
raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).delete_vpn_gateway is not yet implemented') vpn_gateway_id = self.querystring.get('VpnGatewayId')[0]
vpn_gateway = self.ec2_backend.delete_vpn_gateway(vpn_gateway_id)
template = Template(DELETE_VPN_GATEWAY_RESPONSE)
return template.render(vpn_gateway=vpn_gateway)
def describe_vpn_gateways(self): def describe_vpn_gateways(self):
raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).describe_vpn_gateways is not yet implemented') filters = filters_from_querystring(self.querystring)
vpn_gateways = self.ec2_backend.get_all_vpn_gateways(filters)
template = Template(DESCRIBE_VPN_GATEWAYS_RESPONSE)
return template.render(vpn_gateways=vpn_gateways)
def detach_vpn_gateway(self): def detach_vpn_gateway(self):
raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).detach_vpn_gateway is not yet implemented') raise NotImplementedError('VirtualPrivateGateways(AmazonVPC).detach_vpn_gateway is not yet implemented')
CREATE_VPN_GATEWAY_RESPONSE = """
<CreateVpnGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
<vpnGateway>
<vpnGatewayId>{{ vpn_gateway.id }}</vpnGatewayId>
<state>available</state>
<type>{{ vpn_gateway.type }}</type>
<availabilityZone>us-east-1a</availabilityZone>
<attachments/>
<tagSet>
{% for tag in vpn_gateway.get_tags() %}
<item>
<resourceId>{{ tag.resource_id }}</resourceId>
<resourceType>{{ tag.resource_type }}</resourceType>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
</vpnGateway>
</CreateVpnGatewayResponse>"""
DESCRIBE_VPN_GATEWAYS_RESPONSE = """
<DescribeVpnGatewaysResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
<vpnGatewaySet>
{% for vpn_gateway in vpn_gateways %}
<item>
<vpnGatewayId>{{ vpn_gateway.id }}</vpnGatewayId>
<state>available</state>
<type>{{ vpn_gateway.id }}</type>
<availabilityZone>us-east-1a</availabilityZone>
<attachments>
{% for attachment in vpn_gateway.attachments.values() %}
<item>
<vpcId>{{ attachment.vpc_id }}</vpcId>
<state>{{ attachment.state }}</state>
</item>
{% endfor %}
</attachments>
<tagSet/>
<tagSet>
{% for tag in vpn_gateway.get_tags() %}
<item>
<resourceId>{{ tag.resource_id }}</resourceId>
<resourceType>{{ tag.resource_type }}</resourceType>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
</item>
{% endfor %}
</vpnGatewaySet>
</DescribeVpnGatewaysResponse>"""
ATTACH_VPN_GATEWAY_RESPONSE = """
<AttachVpnGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
<attachment>
<vpcId>{{ attachment.vpc_id }}</vpcId>
<state>{{ attachment.state }}</state>
</attachment>
</AttachVpnGatewayResponse>"""
DELETE_VPN_GATEWAY_RESPONSE = """
<DeleteVpnGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
<return>true</return>
</DeleteVpnGatewayResponse>
"""

View File

@ -81,6 +81,10 @@ def random_network_acl_subnet_association_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-acl-subnet-assoc']) return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-acl-subnet-assoc'])
def random_vpn_gateway_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-gateway'])
def random_volume_id(): def random_volume_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['volume']) return random_id(prefix=EC2_RESOURCE_TO_PREFIX['volume'])

View File

@ -7,4 +7,70 @@ from moto import mock_ec2
@mock_ec2 @mock_ec2
def test_virtual_private_gateways(): def test_virtual_private_gateways():
pass conn = boto.connect_vpc('the_key', 'the_secret')
vpn_gateway = conn.create_vpn_gateway('ipsec.1', 'us-east-1a')
vpn_gateway.should_not.be.none
vpn_gateway.id.should.match(r'vgw-\w+')
vpn_gateway.type.should.equal('ipsec.1')
vpn_gateway.state.should.equal('available')
vpn_gateway.availability_zone.should.equal('us-east-1a')
@mock_ec2
def test_describe_vpn_gateway():
conn = boto.connect_vpc('the_key', 'the_secret')
vpn_gateway = conn.create_vpn_gateway('ipsec.1', 'us-east-1a')
vgws = conn.get_all_vpn_gateways()
vgws.should.have.length_of(1)
gateway = vgws[0]
gateway.id.should.match(r'vgw-\w+')
gateway.id.should.equal(vpn_gateway.id)
vpn_gateway.type.should.equal('ipsec.1')
vpn_gateway.state.should.equal('available')
vpn_gateway.availability_zone.should.equal('us-east-1a')
@mock_ec2
def test_vpn_gateway_vpc_attachment():
conn = boto.connect_vpc('the_key', 'the_secret')
vpc = conn.create_vpc("10.0.0.0/16")
vpn_gateway = conn.create_vpn_gateway('ipsec.1', 'us-east-1a')
conn.attach_vpn_gateway(
vpn_gateway_id=vpn_gateway.id,
vpc_id=vpc.id
)
gateway = conn.get_all_vpn_gateways()[0]
attachments = gateway.attachments
attachments.should.have.length_of(1)
attachments[0].vpc_id.should.equal(vpc.id)
attachments[0].state.should.equal('attached')
@mock_ec2
def test_delete_vpn_gateway():
conn = boto.connect_vpc('the_key', 'the_secret')
vpn_gateway = conn.create_vpn_gateway('ipsec.1', 'us-east-1a')
conn.delete_vpn_gateway(vpn_gateway.id)
vgws = conn.get_all_vpn_gateways()
vgws.should.have.length_of(0)
@mock_ec2
def test_vpn_gateway_tagging():
conn = boto.connect_vpc('the_key', 'the_secret')
vpn_gateway = conn.create_vpn_gateway('ipsec.1', 'us-east-1a')
vpn_gateway.add_tag("a key", "some value")
tag = conn.get_all_tags()[0]
tag.name.should.equal("a key")
tag.value.should.equal("some value")
# Refresh the subnet
vpn_gateway = conn.get_all_vpn_gateways()[0]
vpn_gateway.tags.should.have.length_of(1)
vpn_gateway.tags["a key"].should.equal("some value")