From 6d6c2c7b3ed00a9020c175c8f9b392924a872a6a Mon Sep 17 00:00:00 2001 From: Chris DeRamus Date: Fri, 20 Dec 2013 12:56:25 -0500 Subject: [PATCH 1/4] Issue: LIBCLOUD-477 Add list/delete/create network (VPC) calls within EC2 --- libcloud/compute/drivers/ec2.py | 125 ++++++++++++++++++ .../test/compute/fixtures/ec2/create_vpc.xml | 10 ++ .../test/compute/fixtures/ec2/delete_vpc.xml | 4 + .../compute/fixtures/ec2/describe_vpcs.xml | 28 ++++ libcloud/test/compute/test_ec2.py | 43 ++++++ 5 files changed, 210 insertions(+) create mode 100644 libcloud/test/compute/fixtures/ec2/create_vpc.xml create mode 100644 libcloud/test/compute/fixtures/ec2/delete_vpc.xml create mode 100644 libcloud/test/compute/fixtures/ec2/describe_vpcs.xml diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index b94dbdbd71..9cc8281987 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -1236,6 +1236,131 @@ def ex_describe_keypair(self, name): 'keyFingerprint': fingerprint } + def ex_list_networks(self): + """ + Return all private virtual private cloud (VPC) networks + + :return: list of network dicts + :rtype: ``list`` + """ + params = {'Action': 'DescribeVpcs'} + + result = self.connection.request(self.path, + params=params.copy()).object + + # The list which we return + networks = [] + for element in findall(element=result, + xpath='vpcSet/item', + namespace=NAMESPACE): + + # Get the network id + vpc_id = findtext(element=element, + xpath='vpcId', + namespace=NAMESPACE) + + # Get tags + tags = dict((findtext(element=item, + xpath='key', + namespace=NAMESPACE), + findtext(element=item, + xpath='value', + namespace=NAMESPACE)) + for item in findall(element=element, + xpath='tagSet/item', + namespace=NAMESPACE)) + + # Set our name is the Name key/value if available + # If we don't get anything back then use the vpc_id + name = tags.get('Name', vpc_id) + + networks.append({'vpc_id': vpc_id, + 'name': name, + 'state': findtext(element=element, + xpath='state', + namespace=NAMESPACE), + 'cidr_block': findtext(element=element, + xpath='cidrBlock', + namespace=NAMESPACE), + 'dhcp_options_id': findtext(element=element, + xpath='dhcpOptionsId', + namespace=NAMESPACE), + 'tags': tags, + 'instance_tenancy': findtext(element=element, + xpath= + 'instance_tenancy', + namespace=NAMESPACE), + 'is_default': findtext(element=element, + xpath='isDefault', + namespace=NAMESPACE)}) + + return networks + + def ex_create_network(self, cidr_block, name=None, + instance_tenancy='default'): + """ + Create a network/VPC + + :param cidr_block: The CIDR block assigned to the network + :type cidr_block: ``str`` + + :param name: An optional name for the network + :type name: ``str`` + + :param instance_tenancy: The allowed tenancy of instances launched + into the VPC. + Valid values: default/dedicated + :type instance_tenancy: ``str`` + + :return: Dictionary of network properties + :rtype: ``dict`` + """ + params = {'Action': 'CreateVpc', + 'CidrBlock': cidr_block, + 'InstanceTenancy': instance_tenancy} + + result = self.connection.request(self.path, params=params).object + + # Get our properties + response = {'vpc_id': findtext(element=result, + xpath='vpc/vpcId', + namespace=NAMESPACE), + 'state': findtext(element=result, + xpath='vpc/state', + namespace=NAMESPACE), + 'cidr_block': findtext(element=result, + xpath='vpc/cidrBlock', + namespace=NAMESPACE)} + + # Attempt to tag our network if the name was provided + if name is not None: + # Build a resource object + class Resource: + pass + + resource = Resource() + resource.id = response['vpc_id'] + self.ex_create_tags(resource, {'Name': name}) + + return response + + def ex_destroy_network(self, vpc_id): + """ + Deletes a network/VPC. + + :param vpc_id: The ID of the VPC + :type vpc_id: ``str`` + + :rtype: ``bool`` + """ + params = {'Action': 'DeleteVpc', 'VpcId': vpc_id} + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, xpath='return', + namespace=NAMESPACE) + + return element == 'true' + def ex_list_security_groups(self): """ List existing Security Groups. diff --git a/libcloud/test/compute/fixtures/ec2/create_vpc.xml b/libcloud/test/compute/fixtures/ec2/create_vpc.xml new file mode 100644 index 0000000000..70bff318c8 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/create_vpc.xml @@ -0,0 +1,10 @@ + + 7a662fe5-1f34-4e17-9ee9-69a28a8ac0be + + vpc-ad3527cf + pending + 192.168.55.0/24 + dopt-7eded312 + default + + \ No newline at end of file diff --git a/libcloud/test/compute/fixtures/ec2/delete_vpc.xml b/libcloud/test/compute/fixtures/ec2/delete_vpc.xml new file mode 100644 index 0000000000..e402a502fe --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/delete_vpc.xml @@ -0,0 +1,4 @@ + + 85793fa6-2ece-480c-855f-0f82c3257e50 + true + \ No newline at end of file diff --git a/libcloud/test/compute/fixtures/ec2/describe_vpcs.xml b/libcloud/test/compute/fixtures/ec2/describe_vpcs.xml new file mode 100644 index 0000000000..ae1f516a4a --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/describe_vpcs.xml @@ -0,0 +1,28 @@ + + be8cfa34-0710-4895-941f-961c5738f8f8 + + + vpc-532335e1 + available + 192.168.51.0/24 + dopt-7eded312 + + default + false + + + vpc-62ded30e + available + 192.168.51.1/24 + dopt-7eded312 + + + Name + Test VPC + + + default + false + + + \ No newline at end of file diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index d4caacc103..48aaf8db95 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -708,6 +708,37 @@ def test_ex_get_limits(self): 'max-elastic-ips': 5} self.assertEqual(limits['resource'], expected) + def test_ex_list_networks(self): + vpcs = self.driver.ex_list_networks() + + self.assertEqual(len(vpcs), 2) + + self.assertEqual('vpc-532335e1', vpcs[0]['vpc_id']) + self.assertEqual('available', vpcs[0]['state']) + self.assertEqual('dopt-7eded312', vpcs[0]['dhcp_options_id']) + self.assertEqual('vpc-532335e1', vpcs[0]['name']) + + self.assertEqual('vpc-62ded30e', vpcs[1]['vpc_id']) + self.assertEqual('available', vpcs[1]['state']) + self.assertEqual('dopt-7eded312', vpcs[1]['dhcp_options_id']) + self.assertEqual('Test VPC', vpcs[1]['name']) + + def test_ex_create_network(self): + vpc = self.driver.ex_create_network('192.168.55.0/24', + name='Test VPC', + instance_tenancy='default') + + self.assertEqual('vpc-ad3527cf', vpc['vpc_id']) + self.assertEqual('pending', vpc['state']) + self.assertEqual('192.168.55.0/24', vpc['cidr_block']) + + def test_ex_destroy_network(self): + vpcs = self.driver.ex_list_networks() + vpc = vpcs[0] + + resp = self.driver.ex_destroy_network(vpc['vpc_id']) + self.assertTrue(resp) + class EC2USWest1Tests(EC2Tests): region = 'us-west-1' @@ -979,6 +1010,18 @@ def _DescribeAccountAttributes(self, method, url, body, headers): body = self.fixtures.load('describe_account_attributes.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _DescribeVpcs(self, method, url, body, headers): + body = self.fixtures.load('describe_vpcs.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _CreateVpc(self, method, url, body, headers): + body = self.fixtures.load('create_vpc.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _DeleteVpc(self, method, url, body, headers): + body = self.fixtures.load('delete_vpc.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + class EucMockHttp(EC2MockHttp): fixtures = ComputeFileFixtures('ec2') From 7777034875c8d09be6b20a1f3821c715fa1dad75 Mon Sep 17 00:00:00 2001 From: Chris DeRamus Date: Mon, 23 Dec 2013 09:18:04 -0500 Subject: [PATCH 2/4] Changed the return type to a list of EC2Network objects Updated list/delete network tests --- libcloud/compute/drivers/ec2.py | 144 +++++++++++------- .../compute/fixtures/ec2/describe_vpcs.xml | 2 +- libcloud/test/compute/test_ec2.py | 22 +-- 3 files changed, 104 insertions(+), 64 deletions(-) diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 9cc8281987..bd25da7d50 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -503,6 +503,24 @@ def __repr__(self): % (self.name, self.zone_state, self.region_name)) +class EC2Network(object): + """ + Represents information about a VPC (Virtual Private Cloud) network + + Note: This class is EC2 specific. + """ + + def __init__(self, id, name, cidr_block, extra=None): + self.id = id + self.name = name + self.cidr_block = cidr_block + self.extra = extra or {} + + def __repr__(self): + return ((' vpc-62ded30e available - 192.168.51.1/24 + 192.168.52.0/24 dopt-7eded312 diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 48aaf8db95..10412cf456 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -713,15 +713,17 @@ def test_ex_list_networks(self): self.assertEqual(len(vpcs), 2) - self.assertEqual('vpc-532335e1', vpcs[0]['vpc_id']) - self.assertEqual('available', vpcs[0]['state']) - self.assertEqual('dopt-7eded312', vpcs[0]['dhcp_options_id']) - self.assertEqual('vpc-532335e1', vpcs[0]['name']) - - self.assertEqual('vpc-62ded30e', vpcs[1]['vpc_id']) - self.assertEqual('available', vpcs[1]['state']) - self.assertEqual('dopt-7eded312', vpcs[1]['dhcp_options_id']) - self.assertEqual('Test VPC', vpcs[1]['name']) + self.assertEqual('vpc-532335e1', vpcs[0].id) + self.assertEqual('vpc-532335e1', vpcs[0].name) + self.assertEqual('192.168.51.0/24', vpcs[0].cidr_block) + self.assertEqual('available', vpcs[0].extra['state']) + self.assertEqual('dopt-7eded312', vpcs[0].extra['dhcp_options_id']) + + self.assertEqual('vpc-62ded30e', vpcs[1].id) + self.assertEqual('Test VPC', vpcs[1].name) + self.assertEqual('192.168.52.0/24', vpcs[1].cidr_block) + self.assertEqual('available', vpcs[1].extra['state']) + self.assertEqual('dopt-7eded312', vpcs[1].extra['dhcp_options_id']) def test_ex_create_network(self): vpc = self.driver.ex_create_network('192.168.55.0/24', @@ -736,7 +738,7 @@ def test_ex_destroy_network(self): vpcs = self.driver.ex_list_networks() vpc = vpcs[0] - resp = self.driver.ex_destroy_network(vpc['vpc_id']) + resp = self.driver.ex_destroy_network(vpc.id) self.assertTrue(resp) From 78e45c4ead96ddb12f29c14680756aadc37f747a Mon Sep 17 00:00:00 2001 From: Chris DeRamus Date: Tue, 24 Dec 2013 08:33:13 -0500 Subject: [PATCH 3/4] Updated ex_create_network to return an EC2Network object Updated test_ex_create_network accordingly --- libcloud/compute/drivers/ec2.py | 26 ++++++-------------------- libcloud/test/compute/test_ec2.py | 11 +++++------ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 30bd4cdc50..ca43ac2cf7 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -1527,30 +1527,16 @@ def ex_create_network(self, cidr_block, name=None, 'CidrBlock': cidr_block, 'InstanceTenancy': instance_tenancy} - result = self.connection.request(self.path, params=params).object + response = self.connection.request(self.path, params=params).object + element = response.findall(fixxpath(xpath='vpc', + namespace=NAMESPACE))[0] - # Get our properties - response = {'vpc_id': findtext(element=result, - xpath='vpc/vpcId', - namespace=NAMESPACE), - 'state': findtext(element=result, - xpath='vpc/state', - namespace=NAMESPACE), - 'cidr_block': findtext(element=result, - xpath='vpc/cidrBlock', - namespace=NAMESPACE)} + network = self._to_network(element) - # Attempt to tag our network if the name was provided if name is not None: - # Build a resource object - class Resource: - pass - - resource = Resource() - resource.id = response['vpc_id'] - self.ex_create_tags(resource, {'Name': name}) + self.ex_create_tags(network, {'Name': name}) - return response + return network def ex_destroy_network(self, vpc_id): """ diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 2074a5185f..f6bb902e5a 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -800,9 +800,9 @@ def test_ex_create_network(self): name='Test VPC', instance_tenancy='default') - self.assertEqual('vpc-ad3527cf', vpc['vpc_id']) - self.assertEqual('pending', vpc['state']) - self.assertEqual('192.168.55.0/24', vpc['cidr_block']) + self.assertEqual('vpc-ad3527cf', vpc.id) + self.assertEqual('192.168.55.0/24', vpc.cidr_block) + self.assertEqual('pending', vpc.extra['state']) def test_ex_destroy_network(self): vpcs = self.driver.ex_list_networks() @@ -1090,10 +1090,10 @@ def _DescribeAccountAttributes(self, method, url, body, headers): body = self.fixtures.load('describe_account_attributes.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) -<<<<<<< HEAD def _CreateSecurityGroup(self, method, url, body, headers): body = self.fixtures.load('create_security_group.xml') -======= + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _DescribeVpcs(self, method, url, body, headers): body = self.fixtures.load('describe_vpcs.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) @@ -1104,7 +1104,6 @@ def _CreateVpc(self, method, url, body, headers): def _DeleteVpc(self, method, url, body, headers): body = self.fixtures.load('delete_vpc.xml') ->>>>>>> LIBCLOUD-467_Add_VPC_Lifecycle_Support return (httplib.OK, body, {}, httplib.responses[httplib.OK]) From 07c9f146e176d7ce4b4c265ef44c12cd6939f019 Mon Sep 17 00:00:00 2001 From: Chris DeRamus Date: Tue, 24 Dec 2013 10:10:46 -0500 Subject: [PATCH 4/4] Destroy -> Delete --- libcloud/compute/drivers/ec2.py | 2 +- libcloud/test/compute/test_ec2.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index ca43ac2cf7..346d2616e3 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -1538,7 +1538,7 @@ def ex_create_network(self, cidr_block, name=None, return network - def ex_destroy_network(self, vpc_id): + def ex_delete_network(self, vpc_id): """ Deletes a network/VPC. diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index f6bb902e5a..83cdb8da90 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -804,11 +804,11 @@ def test_ex_create_network(self): self.assertEqual('192.168.55.0/24', vpc.cidr_block) self.assertEqual('pending', vpc.extra['state']) - def test_ex_destroy_network(self): + def test_ex_delete_network(self): vpcs = self.driver.ex_list_networks() vpc = vpcs[0] - resp = self.driver.ex_destroy_network(vpc.id) + resp = self.driver.ex_delete_network(vpc.id) self.assertTrue(resp)