LIBCLOUD-525: Add VPC lifecycle support into the EC2 driver. This PR includes the ability to describe, create, delete, attach and detach VPC Internet gateways.
Closes #255 Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/0cdc81fe Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/0cdc81fe Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/0cdc81fe Branch: refs/heads/trunk Commit: 0cdc81fe6c8149409c28a9f77c889aba409870da Parents: badc79a Author: Chris DeRamus <[email protected]> Authored: Sun Mar 2 09:43:27 2014 -0500 Committer: Tomaz Muraus <[email protected]> Committed: Sun Mar 2 16:33:49 2014 +0100 ---------------------------------------------------------------------- libcloud/compute/drivers/ec2.py | 151 +++++++++++++++++++ .../fixtures/ec2/attach_internet_gateway.xml | 4 + .../fixtures/ec2/create_internet_gateway.xml | 8 + .../fixtures/ec2/delete_internet_gateway.xml | 4 + .../fixtures/ec2/describe_internet_gateways.xml | 20 +++ .../fixtures/ec2/detach_internet_gateway.xml | 4 + libcloud/test/compute/test_ec2.py | 52 +++++++ 7 files changed, 243 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/compute/drivers/ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 6222657..58d0ce7 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -1171,6 +1171,24 @@ class ElasticIP(object): % (self.ip, self.domain, self.instance_id)) +class VPCInternetGateway(object): + """ + Class which stores information about VPC Internet Gateways. + + Note: This class is VPC specific. + """ + + def __init__(self, id, name, vpc_id, state, driver, extra=None): + self.id = id + self.name = name + self.vpc_id = vpc_id + self.state = state + self.extra = extra or {} + + def __repr__(self): + return (('<VPCInternetGateway: id=%s>') % (self.id)) + + class BaseEC2NodeDriver(NodeDriver): """ Base Amazon EC2 node driver. @@ -3171,6 +3189,105 @@ class BaseEC2NodeDriver(NodeDriver): return result + def ex_list_internet_gateways(self): + """ + Describes available Internet gateways and whether or not they are + attached to a VPC. These are required for VPC nodes to communicate + over the Internet. + + :rtype: ``list`` of :class:`.VPCInternetGateway` + """ + params = {'Action': 'DescribeInternetGateways'} + + response = self.connection.request(self.path, params=params).object + + return self._to_internet_gateways(response, 'internetGatewaySet/item') + + def ex_create_internet_gateway(self, name=None): + """ + Delete a VPC Internet gateway + + :rtype: ``bool`` + """ + params = {'Action': 'CreateInternetGateway'} + + resp = self.connection.request(self.path, params=params).object + + element = resp.findall(fixxpath(xpath='internetGateway', + namespace=NAMESPACE)) + + gateway = self._to_internet_gateway(element[0], name) + + if name is not None: + self.ex_create_tags(gateway, {'Name': name}) + + return gateway + + def ex_delete_internet_gateway(self, gateway): + """ + Delete a VPC Internet gateway + + :param gateway: The gateway to delete + :type gateway: :class:`.VPCInternetGateway` + + :rtype: ``bool`` + """ + params = {'Action': 'DeleteInternetGateway', + 'InternetGatewayId': gateway.id} + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, + xpath='return', + namespace=NAMESPACE) + + return element == 'true' + + def ex_attach_internet_gateway(self, gateway, network): + """ + Attach a Internet gateway to a VPC + + :param gateway: The gateway to attach + :type gateway: :class:`.VPCInternetGateway` + + :param network: The VPC network to attach to + :type network: :class:`.EC2Network` + + :rtype: ``bool`` + """ + params = {'Action': 'AttachInternetGateway', + 'InternetGatewayId': gateway.id, + 'VpcId': network.id} + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, + xpath='return', + namespace=NAMESPACE) + + return element == 'true' + + def ex_detach_internet_gateway(self, gateway, network): + """ + Detach a Internet gateway from a VPC + + :param gateway: The gateway to detach + :type gateway: :class:`.VPCInternetGateway` + + :param network: The VPC network to detach from + :type network: :class:`.EC2Network` + + :rtype: ``bool`` + """ + params = {'Action': 'DetachInternetGateway', + 'InternetGatewayId': gateway.id, + 'VpcId': network.id} + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, + xpath='return', + namespace=NAMESPACE) + + return element == 'true' + def _to_nodes(self, object, xpath): return [self._to_node(el) for el in object.findall(fixxpath(xpath=xpath, @@ -3557,6 +3674,40 @@ class BaseEC2NodeDriver(NodeDriver): return mapping + def _to_internet_gateways(self, object, xpath): + return [self._to_internet_gateway(el) + for el in object.findall(fixxpath(xpath=xpath, + namespace=NAMESPACE))] + + def _to_internet_gateway(self, element, name=None): + id = findtext(element=element, + xpath='internetGatewayId', + namespace=NAMESPACE) + + vpc_id = findtext(element=element, + xpath='attachmentSet/item/vpcId', + namespace=NAMESPACE) + + state = findtext(element=element, + xpath='attachmentSet/item/state', + namespace=NAMESPACE) + + # If there's no attachment state, let's + # set it to available + if not state: + state = 'available' + + # Get our tags + tags = self._get_resource_tags(element) + + # If name was not passed into the method then + # fall back then use the gateway id + name = name if name else tags.get('Name', id) + + return VPCInternetGateway(id=id, name=name, vpc_id=vpc_id, + state=state, driver=self.connection.driver, + extra={'tags': tags}) + def _pathlist(self, key, arr): """ Converts a key and an array of values into AWS query param format. http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/fixtures/ec2/attach_internet_gateway.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/attach_internet_gateway.xml b/libcloud/test/compute/fixtures/ec2/attach_internet_gateway.xml new file mode 100644 index 0000000..852ec39 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/attach_internet_gateway.xml @@ -0,0 +1,4 @@ +<AttachInternetGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>1eb45fd7-d4f6-4b63-a52f-54fc0c82617e</requestId> + <return>true</return> +</AttachInternetGatewayResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/fixtures/ec2/create_internet_gateway.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/create_internet_gateway.xml b/libcloud/test/compute/fixtures/ec2/create_internet_gateway.xml new file mode 100644 index 0000000..0891423 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/create_internet_gateway.xml @@ -0,0 +1,8 @@ +<CreateInternetGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>437b9824-8143-4583-98f7-0937d53aea83</requestId> + <internetGateway> + <internetGatewayId>igw-13ac2b36</internetGatewayId> + <attachmentSet/> + <tagSet/> + </internetGateway> +</CreateInternetGatewayResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/fixtures/ec2/delete_internet_gateway.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/delete_internet_gateway.xml b/libcloud/test/compute/fixtures/ec2/delete_internet_gateway.xml new file mode 100644 index 0000000..619ab54 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/delete_internet_gateway.xml @@ -0,0 +1,4 @@ +<DeleteInternetGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>b1a5c8c9-91c7-43f3-8234-c162db89a2df</requestId> + <return>true</return> +</DeleteInternetGatewayResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/fixtures/ec2/describe_internet_gateways.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/describe_internet_gateways.xml b/libcloud/test/compute/fixtures/ec2/describe_internet_gateways.xml new file mode 100644 index 0000000..44c7185 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/describe_internet_gateways.xml @@ -0,0 +1,20 @@ +<DescribeInternetGatewaysResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>843ff26c-f1ac-48f5-93a6-fa28f8abd9dd</requestId> + <internetGatewaySet> + <item> + <internetGatewayId>igw-84dd3ae1</internetGatewayId> + <attachmentSet/> + <tagSet/> + </item> + <item> + <internetGatewayId>igw-7fdae215</internetGatewayId> + <attachmentSet> + <item> + <vpcId>vpc-62cad41e</vpcId> + <state>available</state> + </item> + </attachmentSet> + <tagSet/> + </item> + </internetGatewaySet> +</DescribeInternetGatewaysResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/fixtures/ec2/detach_internet_gateway.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/detach_internet_gateway.xml b/libcloud/test/compute/fixtures/ec2/detach_internet_gateway.xml new file mode 100644 index 0000000..8fa1e50 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/detach_internet_gateway.xml @@ -0,0 +1,4 @@ +<DetachInternetGatewayResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>7098cc6d-a984-4d34-a5ed-6ae1a645c0b6</requestId> + <return>true</return> +</DetachInternetGatewayResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/0cdc81fe/libcloud/test/compute/test_ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 63f15aa..1a3cb20 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -995,6 +995,38 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin): resp = self.driver.ex_detach_network_interface('eni-attach-2b588b47') self.assertTrue(resp) + def test_ex_list_internet_gateways(self): + gateways = self.driver.ex_list_internet_gateways() + + self.assertEqual(len(gateways), 2) + + self.assertEqual('igw-84dd3ae1', gateways[0].id) + self.assertEqual('igw-7fdae215', gateways[1].id) + self.assertEqual('available', gateways[1].state) + self.assertEqual('vpc-62cad41e', gateways[1].vpc_id) + + def test_ex_create_internet_gateway(self): + gateway = self.driver.ex_create_internet_gateway() + + self.assertEqual('igw-13ac2b36', gateway.id) + + def test_ex_delete_internet_gateway(self): + gateway = self.driver.ex_list_internet_gateways()[0] + resp = self.driver.ex_delete_internet_gateway(gateway) + self.assertTrue(resp) + + def test_ex_attach_internet_gateway(self): + gateway = self.driver.ex_list_internet_gateways()[0] + network = self.driver.ex_list_networks()[0] + resp = self.driver.ex_attach_internet_gateway(gateway, network) + self.assertTrue(resp) + + def test_ex_detach_internet_gateway(self): + gateway = self.driver.ex_list_internet_gateways()[0] + network = self.driver.ex_list_networks()[0] + resp = self.driver.ex_detach_internet_gateway(gateway, network) + self.assertTrue(resp) + class EC2USWest1Tests(EC2Tests): region = 'us-west-1' @@ -1346,6 +1378,26 @@ class EC2MockHttp(MockHttpTestCase): body = self.fixtures.load('detach_network_interface.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _DescribeInternetGateways(self, method, url, body, headers): + body = self.fixtures.load('describe_internet_gateways.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _CreateInternetGateway(self, method, url, body, headers): + body = self.fixtures.load('create_internet_gateway.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _DeleteInternetGateway(self, method, url, body, headers): + body = self.fixtures.load('delete_internet_gateway.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _AttachInternetGateway(self, method, url, body, headers): + body = self.fixtures.load('attach_internet_gateway.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _DetachInternetGateway(self, method, url, body, headers): + body = self.fixtures.load('detach_internet_gateway.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + class EucMockHttp(EC2MockHttp): fixtures = ComputeFileFixtures('ec2')
