diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py
index 3c181e045..5c3d64727 100644
--- a/moto/ec2/exceptions.py
+++ b/moto/ec2/exceptions.py
@@ -84,6 +84,14 @@ class InvalidVpnGatewayIdError(EC2ClientError):
.format(network_acl_id))
+class InvalidVpnConnectionIdError(EC2ClientError):
+ def __init__(self, network_acl_id):
+ super(InvalidVpnConnectionIdError, self).__init__(
+ "InvalidVpnConnectionID.NotFound",
+ "The vpnConnection ID '{0}' does not exist"
+ .format(network_acl_id))
+
+
class InvalidNetworkInterfaceIdError(EC2ClientError):
def __init__(self, eni_id):
super(InvalidNetworkInterfaceIdError, self).__init__(
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
index 446561d33..0d7163866 100644
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -54,7 +54,8 @@ from .exceptions import (
InvalidID,
InvalidCIDRSubnetError,
InvalidNetworkAclIdError,
- InvalidVpnGatewayIdError
+ InvalidVpnGatewayIdError,
+ InvalidVpnConnectionIdError
)
from .utils import (
EC2_RESOURCE_TO_PREFIX,
@@ -93,6 +94,7 @@ from .utils import (
random_network_acl_id,
random_network_acl_subnet_association_id,
random_vpn_gateway_id,
+ random_vpn_connection_id,
is_tag_filter,
)
@@ -2512,6 +2514,70 @@ class DHCPOptionsSetBackend(object):
return True
+class VPNConnection(TaggedEC2Resource):
+ def __init__(self, ec2_backend, id, type,
+ customer_gateway_id, vpn_gateway_id):
+ self.ec2_backend = ec2_backend
+ self.id = id
+ self.state = 'available'
+ self.customer_gateway_configuration = {}
+ self.type = type
+ self.customer_gateway_id = customer_gateway_id
+ self.vpn_gateway_id = vpn_gateway_id
+ self.tunnels = None
+ self.options = None
+ self.static_routes = None
+
+
+class VPNConnectionBackend(object):
+ def __init__(self):
+ self.vpn_connections = {}
+ super(VPNConnectionBackend, self).__init__()
+
+ def create_vpn_connection(self, type, customer_gateway_id,
+ vpn_gateway_id,
+ static_routes_only=None):
+ vpn_connection_id = random_vpn_connection_id()
+ if static_routes_only:
+ pass
+ vpn_connection = VPNConnection(
+ self, id=vpn_connection_id, type=type,
+ customer_gateway_id=customer_gateway_id,
+ vpn_gateway_id=vpn_gateway_id
+ )
+ self.vpn_connections[vpn_connection.id] = vpn_connection
+ return vpn_connection
+
+ def delete_vpn_connection(self, vpn_connection_id):
+
+ if vpn_connection_id in self.vpn_connections:
+ self.vpn_connections.pop(vpn_connection_id)
+ else:
+ raise InvalidVpnConnectionIdError(vpn_connection_id)
+ return True
+
+ def describe_vpn_connections(self, vpn_connection_ids=None):
+ vpn_connections = []
+ for vpn_connection_id in vpn_connection_ids or []:
+ if vpn_connection_id in self.vpn_connections:
+ vpn_connections.append(self.vpn_connections[vpn_connection_id])
+ else:
+ raise InvalidVpnConnectionIdError(vpn_connection_id)
+ return vpn_connections or self.vpn_connections.values()
+
+ def get_all_vpn_connections(self, vpn_connection_ids=None, filters=None):
+ vpn_connections = self.vpn_connections.values()
+
+ if vpn_connection_ids:
+ vpn_connections = [vpn_connection for vpn_connection in vpn_connections
+ if vpn_connection.id in vpn_connection_ids]
+ if len(vpn_connections) != len(vpn_connection_ids):
+ invalid_id = list(set(vpn_connection_ids).difference(set([vpn_connection.id for vpn_connection in vpn_connections])))[0]
+ raise InvalidVpnConnectionIdError(invalid_id)
+
+ return generic_filter(filters, vpn_connections)
+
+
class NetworkAclBackend(object):
def __init__(self):
self.network_acls = {}
@@ -2707,7 +2773,7 @@ class VpnGatewayBackend(object):
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend,
VPCBackend, SubnetBackend, SubnetRouteTableAssociationBackend,
- NetworkInterfaceBackend,
+ NetworkInterfaceBackend, VPNConnectionBackend,
VPCPeeringConnectionBackend,
RouteTableBackend, RouteBackend, InternetGatewayBackend,
VPCGatewayAttachmentBackend, SpotRequestBackend,
@@ -2769,7 +2835,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpc-peering-connection']:
self.get_vpc_peering_connection(vpc_pcx_id=resource_id)
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-connection']:
- self.raise_not_implemented_error('DescribeVpnConnections')
+ self.describe_vpn_connections(vpn_connection_ids=[resource_id])
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['vpn-gateway']:
self.get_vpn_gateway(vpn_gateway_id=resource_id)
return True
diff --git a/moto/ec2/responses/vpn_connections.py b/moto/ec2/responses/vpn_connections.py
index ad947efec..e01fd272e 100644
--- a/moto/ec2/responses/vpn_connections.py
+++ b/moto/ec2/responses/vpn_connections.py
@@ -1,13 +1,321 @@
from __future__ import unicode_literals
from moto.core.responses import BaseResponse
+from moto.ec2.utils import filters_from_querystring, vpn_connection_ids_from_query_string
class VPNConnections(BaseResponse):
def create_vpn_connection(self):
- raise NotImplementedError('VPNConnections(AmazonVPC).create_vpn_connection is not yet implemented')
+ type = self.querystring.get("Type", [None])[0]
+ cgw_id = self.querystring.get("CustomerGatewayId", [None])[0]
+ vgw_id = self.querystring.get("VPNGatewayId", [None])[0]
+ static_routes = self.querystring.get("StaticRoutesOnly", [None])[0]
+ vpn_connection = self.ec2_backend.create_vpn_connection(type, cgw_id, vgw_id, static_routes_only=static_routes)
+ template = self.response_template(CREATE_VPN_CONNECTION_RESPONSE)
+ return template.render(vpn_connection=vpn_connection)
def delete_vpn_connection(self):
- raise NotImplementedError('VPNConnections(AmazonVPC).delete_vpn_connection is not yet implemented')
+ vpn_connection_id = self.querystring.get('VpnConnectionId')[0]
+ vpn_connection = self.ec2_backend.delete_vpn_connection(vpn_connection_id)
+ template = self.response_template(DELETE_VPN_CONNECTION_RESPONSE)
+ return template.render(vpn_connection=vpn_connection)
def describe_vpn_connections(self):
- raise NotImplementedError('VPNConnections(AmazonVPC).describe_vpn_connections is not yet implemented')
+ vpn_connection_ids = vpn_connection_ids_from_query_string(self.querystring)
+ filters = filters_from_querystring(self.querystring)
+ vpn_connections = self.ec2_backend.get_all_vpn_connections(
+ vpn_connection_ids=vpn_connection_ids, filters=filters)
+ template = self.response_template(DESCRIBE_VPN_CONNECTION_RESPONSE)
+ return template.render(vpn_connections=vpn_connections)
+
+
+CREATE_VPN_CONNECTION_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+
+ {{ vpn_connection.id }}
+ pending
+
+
+ {{ vpn_connection.customer_gateway_id }}
+ {{ vpn_connection.vpn_gateway_id }}
+ ipsec.1
+
+
+
+ 12.1.2.3
+
+
+ 169.254.44.42
+ 255.255.255.252
+ 30
+
+
+ 65000
+ 30
+
+
+
+
+ 52.2.144.13
+
+
+ 169.254.44.41
+ 255.255.255.252
+ 30
+
+
+ 7224
+ 30
+
+
+
+ sha1
+ aes-128-cbc
+ 28800
+ group2
+ main
+ Iw2IAN9XUsQeYUrkMGP3kP59ugFDkfHg
+
+
+ esp
+ hmac-sha1-96
+ aes-128-cbc
+ 3600
+ group2
+ tunnel
+ true
+ true
+ 1387
+
+ 10
+ 3
+
+
+
+
+
+
+ 12.1.2.3
+
+
+ 169.254.44.42
+ 255.255.255.252
+ 30
+
+
+ 65000
+ 30
+
+
+
+
+ 52.2.144.13
+
+
+ 169.254.44.41
+ 255.255.255.252
+ 30
+
+
+ 7224
+ 30
+
+
+
+ sha1
+ aes-128-cbc
+ 28800
+ group2
+ main
+ Iw2IAN9XUsQeYUrkMGP3kP59ugFDkfHg
+
+
+ esp
+ hmac-sha1-96
+ aes-128-cbc
+ 3600
+ group2
+ tunnel
+ true
+ true
+ 1387
+
+ 10
+ 3
+
+
+
+
+
+ ipsec.1
+ {{ vpn_connection.customer_gateway_id }}
+ {{ vpn_connection.vpn_gateway_id }}
+
+ {% for tag in vpn_connection.get_tags() %}
+ -
+ {{ tag.resource_id }}
+ {{ tag.resource_type }}
+ {{ tag.key }}
+ {{ tag.value }}
+
+ {% endfor %}
+
+
+"""
+
+CREATE_VPN_CONNECTION_ROUTE_RESPONSE = """
+
+ 4f35a1b2-c2c3-4093-b51f-abb9d7311990
+ true
+"""
+
+DELETE_VPN_CONNECTION_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+ true
+"""
+
+DELETE_VPN_CONNECTION_ROUTE_RESPONSE = """
+
+ 4f35a1b2-c2c3-4093-b51f-abb9d7311990
+ true
+"""
+
+DESCRIBE_VPN_CONNECTION_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+
+ {% for vpn_connection in vpn_connections %}
+ -
+ {{ vpn_connection.id }}
+ available
+
+
+ {{ vpn_connection.customer_gateway_id }}
+ {{ vpn_connection.vpn_gateway_id }}
+ ipsec.1
+
+
+
+ 12.1.2.3
+
+
+ 169.254.44.42
+ 255.255.255.252
+ 30
+
+
+ 65000
+ 30
+
+
+
+
+ 52.2.144.13
+
+
+ 169.254.44.41
+ 255.255.255.252
+ 30
+
+
+ 7224
+ 30
+
+
+
+ sha1
+ aes-128-cbc
+ 28800
+ group2
+ main
+ Iw2IAN9XUsQeYUrkMGP3kP59ugFDkfHg
+
+
+ esp
+ hmac-sha1-96
+ aes-128-cbc
+ 3600
+ group2
+ tunnel
+ true
+ true
+ 1387
+
+ 10
+ 3
+
+
+
+
+
+
+ 12.1.2.3
+
+
+ 169.254.44.42
+ 255.255.255.252
+ 30
+
+
+ 65000
+ 30
+
+
+
+
+ 52.2.144.13
+
+
+ 169.254.44.41
+ 255.255.255.252
+ 30
+
+
+ 7224
+ 30
+
+
+
+ sha1
+ aes-128-cbc
+ 28800
+ group2
+ main
+ Iw2IAN9XUsQeYUrkMGP3kP59ugFDkfHg
+
+
+ esp
+ hmac-sha1-96
+ aes-128-cbc
+ 3600
+ group2
+ tunnel
+ true
+ true
+ 1387
+
+ 10
+ 3
+
+
+
+
+
+ ipsec.1
+ {{ vpn_connection.customer_gateway_id }}
+ {{ vpn_connection.vpn_gateway_id }}
+
+ {% for tag in vpn_connection.get_tags() %}
+
-
+ {{ tag.resource_id }}
+ {{ tag.resource_type }}
+ {{ tag.key }}
+ {{ tag.value }}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+"""
diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py
index b16c363ea..70adf2634 100644
--- a/moto/ec2/utils.py
+++ b/moto/ec2/utils.py
@@ -85,6 +85,10 @@ def random_vpn_gateway_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-gateway'])
+def random_vpn_connection_id():
+ return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-connection'])
+
+
def random_volume_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['volume'])
@@ -193,6 +197,14 @@ def vpc_ids_from_querystring(querystring_dict):
return vpc_ids
+def vpn_connection_ids_from_query_string(querystring_dict):
+ vpn_connection_ids = []
+ for key, value in querystring_dict.items():
+ if 'VpnConnectionId' in key:
+ vpn_connection_ids.append(value[0])
+ return vpn_connection_ids
+
+
def sequence_from_querystring(parameter, querystring_dict):
parameter_values = []
for key, value in querystring_dict.items():