diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py
index 5c3d64727..9e8f93004 100644
--- a/moto/ec2/exceptions.py
+++ b/moto/ec2/exceptions.py
@@ -92,6 +92,14 @@ class InvalidVpnConnectionIdError(EC2ClientError):
.format(network_acl_id))
+class InvalidCustomerGatewayIdError(EC2ClientError):
+ def __init__(self, customer_gateway_id):
+ super(InvalidCustomerGatewayIdError, self).__init__(
+ "InvalidCustomerGatewayID.NotFound",
+ "The customer gateway ID '{0}' does not exist"
+ .format(customer_gateway_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 4ae2c00c3..501615722 100644
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -55,7 +55,8 @@ from .exceptions import (
InvalidCIDRSubnetError,
InvalidNetworkAclIdError,
InvalidVpnGatewayIdError,
- InvalidVpnConnectionIdError
+ InvalidVpnConnectionIdError,
+ InvalidCustomerGatewayIdError,
)
from .utils import (
EC2_RESOURCE_TO_PREFIX,
@@ -95,6 +96,7 @@ from .utils import (
random_network_acl_subnet_association_id,
random_vpn_gateway_id,
random_vpn_connection_id,
+ random_customer_gateway_id,
is_tag_filter,
)
@@ -2798,6 +2800,45 @@ class VpnGatewayBackend(object):
return detached
+class CustomerGateway(TaggedEC2Resource):
+ def __init__(self, ec2_backend, id, type, ip_address, bgp_asn):
+ self.ec2_backend = ec2_backend
+ self.id = id
+ self.type = type
+ self.ip_address = ip_address
+ self.bgp_asn = bgp_asn
+ self.attachments = {}
+ super(CustomerGateway, self).__init__()
+
+
+class CustomerGatewayBackend(object):
+ def __init__(self):
+ self.customer_gateways = {}
+ super(CustomerGatewayBackend, self).__init__()
+
+ def create_customer_gateway(self, type='ipsec.1', ip_address=None, bgp_asn=None):
+ customer_gateway_id = random_customer_gateway_id()
+ customer_gateway = CustomerGateway(self, customer_gateway_id, type, ip_address, bgp_asn)
+ self.customer_gateways[customer_gateway_id] = customer_gateway
+ return customer_gateway
+
+ def get_all_customer_gateways(self, filters=None):
+ customer_gateways = self.customer_gateways.values()
+ return generic_filter(filters, customer_gateways)
+
+ def get_customer_gateway(self, customer_gateway_id):
+ customer_gateway = self.customer_gateways.get(customer_gateway_id, None)
+ if not customer_gateway:
+ raise InvalidCustomerGatewayIdError(customer_gateway_id)
+ return customer_gateway
+
+ def delete_customer_gateway(self, customer_gateway_id):
+ deleted = self.customer_gateways.pop(customer_gateway_id, None)
+ if not deleted:
+ raise InvalidCustomerGatewayIdError(customer_gateway_id)
+ return deleted
+
+
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend,
VPCBackend, SubnetBackend, SubnetRouteTableAssociationBackend,
@@ -2806,7 +2847,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RouteTableBackend, RouteBackend, InternetGatewayBackend,
VPCGatewayAttachmentBackend, SpotRequestBackend,
ElasticAddressBackend, KeyPairBackend, DHCPOptionsSetBackend,
- NetworkAclBackend, VpnGatewayBackend):
+ NetworkAclBackend, VpnGatewayBackend, CustomerGatewayBackend):
def __init__(self, region_name):
super(EC2Backend, self).__init__()
@@ -2831,7 +2872,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
for resource_id in resource_ids:
resource_prefix = get_prefix(resource_id)
if resource_prefix == EC2_RESOURCE_TO_PREFIX['customer-gateway']:
- self.raise_not_implemented_error('DescribeCustomerGateways')
+ self.get_customer_gateway(customer_gateway_id=resource_id)
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['dhcp-options']:
self.describe_dhcp_options(options_ids=[resource_id])
elif resource_prefix == EC2_RESOURCE_TO_PREFIX['image']:
diff --git a/moto/ec2/responses/customer_gateways.py b/moto/ec2/responses/customer_gateways.py
index 150ed755b..a6d460c88 100644
--- a/moto/ec2/responses/customer_gateways.py
+++ b/moto/ec2/responses/customer_gateways.py
@@ -1,13 +1,82 @@
from __future__ import unicode_literals
from moto.core.responses import BaseResponse
+from moto.ec2.utils import filters_from_querystring
class CustomerGateways(BaseResponse):
+
def create_customer_gateway(self):
- raise NotImplementedError('CustomerGateways(AmazonVPC).create_customer_gateway is not yet implemented')
+ # raise NotImplementedError('CustomerGateways(AmazonVPC).create_customer_gateway is not yet implemented')
+ type = self.querystring.get('Type', None)[0]
+ ip_address = self.querystring.get('IpAddress', None)[0]
+ bgp_asn = self.querystring.get('BgpAsn', None)[0]
+ customer_gateway = self.ec2_backend.create_customer_gateway(type, ip_address=ip_address, bgp_asn=bgp_asn)
+ template = self.response_template(CREATE_CUSTOMER_GATEWAY_RESPONSE)
+ return template.render(customer_gateway=customer_gateway)
def delete_customer_gateway(self):
- raise NotImplementedError('CustomerGateways(AmazonVPC).delete_customer_gateway is not yet implemented')
+ customer_gateway_id = self.querystring.get('CustomerGatewayId')[0]
+ delete_status = self.ec2_backend.delete_customer_gateway(customer_gateway_id)
+ template = self.response_template(DELETE_CUSTOMER_GATEWAY_RESPONSE)
+ return template.render(customer_gateway=delete_status)
def describe_customer_gateways(self):
- raise NotImplementedError('CustomerGateways(AmazonVPC).describe_customer_gateways is not yet implemented')
+ filters = filters_from_querystring(self.querystring)
+ customer_gateways = self.ec2_backend.get_all_customer_gateways(filters)
+ template = self.response_template(DESCRIBE_CUSTOMER_GATEWAYS_RESPONSE)
+ return template.render(customer_gateways=customer_gateways)
+
+
+CREATE_CUSTOMER_GATEWAY_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+
+ {{ customer_gateway.id }}
+ pending
+ {{ customer_gateway.type }}
+ {{ customer_gateway.ip_address }}
+ {{ customer_gateway.bgp_asn }}
+
+ {% for tag in customer_gateway.get_tags() %}
+ -
+ {{ tag.resource_id }}
+ {{ tag.resource_type }}
+ {{ tag.key }}
+ {{ tag.value }}
+
+ {% endfor %}
+
+
+"""
+
+DELETE_CUSTOMER_GATEWAY_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+ {{ delete_status }}
+"""
+
+DESCRIBE_CUSTOMER_GATEWAYS_RESPONSE = """
+
+ 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE
+
+ {% for customer_gateway in customer_gateways %}
+ -
+ {{ customer_gateway.id }}
+ {{ customer_gateway.state }}
+ available
+ {{ customer_gateway.ip_address }}
+ {{ customer_gateway.bgp_asn }}
+
+ {% for tag in customer_gateway.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 e0edde7d6..5b7743bf4 100644
--- a/moto/ec2/utils.py
+++ b/moto/ec2/utils.py
@@ -89,6 +89,10 @@ def random_vpn_connection_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-connection'])
+def random_customer_gateway_id():
+ return random_id(prefix=EC2_RESOURCE_TO_PREFIX['customer-gateway'])
+
+
def random_volume_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['volume'])
@@ -314,7 +318,7 @@ def get_object_value(obj, attr):
def is_tag_filter(filter_name):
- return (filter_name.startswith('tag:') or
+ return (filter_name.startswith('tag:') or
filter_name.startswith('tag-value') or
filter_name.startswith('tag-key'))
diff --git a/tests/test_ec2/test_customer_gateways.py b/tests/test_ec2/test_customer_gateways.py
index 80fddf287..efd6ce993 100644
--- a/tests/test_ec2/test_customer_gateways.py
+++ b/tests/test_ec2/test_customer_gateways.py
@@ -1,10 +1,46 @@
from __future__ import unicode_literals
import boto
import sure # noqa
+from nose.tools import assert_raises
+from nose.tools import assert_false
+from boto.exception import EC2ResponseError
from moto import mock_ec2
@mock_ec2
-def test_customer_gateways():
- pass
+def test_create_customer_gateways():
+ conn = boto.connect_vpc('the_key', 'the_secret')
+
+ customer_gateway = conn.create_customer_gateway('ipsec.1', '205.251.242.54', 65534)
+ customer_gateway.should_not.be.none
+ customer_gateway.id.should.match(r'cgw-\w+')
+ customer_gateway.type.should.equal('ipsec.1')
+ customer_gateway.bgp_asn.should.equal(65534)
+ customer_gateway.ip_address.should.equal('205.251.242.54')
+
+@mock_ec2
+def test_describe_customer_gateways():
+ conn = boto.connect_vpc('the_key', 'the_secret')
+ customer_gateway = conn.create_customer_gateway('ipsec.1', '205.251.242.54', 65534)
+ cgws = conn.get_all_customer_gateways()
+ cgws.should.have.length_of(1)
+ cgws[0].id.should.match(customer_gateway.id)
+
+@mock_ec2
+def test_delete_customer_gateways():
+ conn = boto.connect_vpc('the_key', 'the_secret')
+
+ customer_gateway = conn.create_customer_gateway('ipsec.1', '205.251.242.54', 65534)
+ customer_gateway.should_not.be.none
+ cgws = conn.get_all_customer_gateways()
+ cgws[0].id.should.match(customer_gateway.id)
+ deleted = conn.delete_customer_gateway(customer_gateway.id)
+ cgws = conn.get_all_customer_gateways()
+ cgws.should.have.length_of(0)
+
+@mock_ec2
+def test_delete_customer_gateways_bad_id():
+ conn = boto.connect_vpc('the_key', 'the_secret')
+ with assert_raises(EC2ResponseError) as cm:
+ conn.delete_customer_gateway('cgw-0123abcd')