From 8b9de60c77aad00079238826815af13d6d340fd1 Mon Sep 17 00:00:00 2001 From: Kyle Long Date: Wed, 30 Sep 2015 11:56:10 -0500 Subject: [PATCH 1/3] adding ex_assign_public_id to create_node One important thing to note is that the node returned will not have a public_ip assigned since it takes a few seconds for amazon to assign the public_ip (or at least for it to get returned through the API). --- libcloud/compute/drivers/ec2.py | 42 ++++++++- ...stances_with_subnet_and_security_group.xml | 87 +++++++++++++++++++ libcloud/test/compute/test_ec2.py | 31 +++++++ 3 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 9930f7374d..dfeee7cbec 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -2312,6 +2312,15 @@ def create_node(self, **kwargs): :keyword ex_placement_group: The name of the placement group to launch the instance into. :type ex_placement_group: ``str`` + + :keyword ex_assign_public_ip: If True, the instance will + be assigned a public ip address. + Note : It takes takes a short + while for the instance to be + assigned the public ip so the + node returned will NOT have + the public ip assigned yet. + :type ex_assign_public_ip: ``bool`` """ image = kwargs["image"] size = kwargs["size"] @@ -2345,13 +2354,14 @@ def create_node(self, **kwargs): ' combinated with ex_subnet') security_group_ids = kwargs.get('ex_security_group_ids', None) + security_group_id_params = {} if security_group_ids: if not isinstance(security_group_ids, (tuple, list)): security_group_ids = [security_group_ids] for sig in range(len(security_group_ids)): - params['SecurityGroupId.%d' % (sig + 1,)] =\ + security_group_id_params['SecurityGroupId.%d' % (sig + 1,)] =\ security_group_ids[sig] if 'location' in kwargs: @@ -2397,12 +2407,40 @@ def create_node(self, **kwargs): if 'ex_ebs_optimized' in kwargs: params['EbsOptimized'] = kwargs['ex_ebs_optimized'] + subnet_id = None if 'ex_subnet' in kwargs: - params['SubnetId'] = kwargs['ex_subnet'].id + subnet_id = kwargs['ex_subnet'].id if 'ex_placement_group' in kwargs and kwargs['ex_placement_group']: params['Placement.GroupName'] = kwargs['ex_placement_group'] + assign_public_ip = kwargs.get('ex_assign_public_ip', False) + # In the event that a public ip is requested a NetworkInterface + # needs to be specified. Some properties that would + # normally be at the root (security group ids and subnet id) + # need to be moved to the level of the NetworkInterface because + # the NetworkInterface is no longer created implicitly + if assign_public_ip: + root_key = 'NetworkInterface.1.' + params[root_key + 'AssociatePublicIpAddress'] = "true" + # This means that when the instance is terminated, the + # NetworkInterface we created for the instance will be + # deleted automatically + params[root_key + 'DeleteOnTermination'] = "true" + # Required to be 0 if we are associating a public ip + params[root_key + 'DeviceIndex'] = "0" + + if subnet_id: + params[root_key + 'SubnetId'] = subnet_id + + for key, security_group_id in security_group_id_params.items(): + key = root_key + key + params[key] = security_group_id + else: + params.update(security_group_id_params) + if subnet_id: + params['SubnetId'] = subnet_id + object = self.connection.request(self.path, params=params).object nodes = self._to_nodes(object, 'instancesSet/item') diff --git a/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml b/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml new file mode 100644 index 0000000000..5ebb5fdb6f --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml @@ -0,0 +1,87 @@ + + + ebfcb9e2-fe5f-4afd-ac91-6a9946305e32 + r-11111111 + 111111111111 + + + + i-11111111 + ami-11111111 + + 0 + pending + + ip-192-168-79-96.us-east-1.compute.internal + + + 0 + + m3.medium + 2015-09-30T14:37:59.000Z + + us-east-1a + + default + + aki-111111111 + + disabled + + subnet-11111111 + vpc-11111111 + 192.168.79.96 + true + + + sg-11111111 + test-security-group + + + + pending + pending + + x86_64 + ebs + /dev/sda + + paravirtual + + xen + + + eni-11111111 + subnet-11111111 + vpc-11111111 + + 111111111111 + in-use + 06:ea:24:17:f7:77 + 192.168.79.96 + true + + + sg-11111111 + test-security-group + + + + eni-attach-11111111 + 0 + attaching + 2015-09-30T14:37:59.000Z + true + + + + 192.168.79.96 + true + + + + + false + + + diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 6a5cdeb9f6..a1ff899c05 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -116,6 +116,26 @@ def test_create_node_with_ex_mincount(self): self.assertEqual(node.extra['tags']['Name'], 'foo') self.assertEqual(len(node.extra['tags']), 1) + def test_create_node_with_ex_assign_public_ip(self): + # assertions are done in _create_ex_assign_public_ip_RunInstances + EC2MockHttp.type = 'create_ex_assign_public_ip' + image = NodeImage(id='ami-11111111', + name=self.image_name, + driver=self.driver) + size = NodeSize('m1.small', 'Small Instance', None, None, None, None, + driver=self.driver) + subnet = EC2NetworkSubnet('subnet-11111111', "test_subnet", "pending") + self.driver.create_node( + name='foo', + image=image, + size=size, + ex_subnet=subnet, + ex_security_group_ids=[ + 'sg-11111111' + ], + ex_assign_public_ip=True, + ) + def test_create_node_with_metadata(self): image = NodeImage(id='ami-be3adfd7', name=self.image_name, @@ -1245,6 +1265,17 @@ def _RunInstances(self, method, url, body, headers): body = self.fixtures.load('run_instances.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _create_ex_assign_public_ip_RunInstances(self, method, url, body, headers): + self.assertUrlContainsQueryParams(url, { + 'NetworkInterface.1.AssociatePublicIpAddress': "true", + 'NetworkInterface.1.DeleteOnTermination': "true", + 'NetworkInterface.1.DeviceIndex': "0", + 'NetworkInterface.1.SubnetId': "subnet-11111111", + 'NetworkInterface.1.SecurityGroupId.1': "sg-11111111", + }) + body = self.fixtures.load('run_instances_with_subnet_and_security_group.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _ex_security_groups_RunInstances(self, method, url, body, headers): self.assertUrlContainsQueryParams(url, {'SecurityGroup.1': 'group1'}) self.assertUrlContainsQueryParams(url, {'SecurityGroup.2': 'group2'}) From 5f6d8e843142e7a0f88d953a253e6541d206d7ef Mon Sep 17 00:00:00 2001 From: Kyle Long Date: Wed, 30 Sep 2015 12:16:32 -0500 Subject: [PATCH 2/3] adding my change --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 50beb3809d..a506003ae9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -31,6 +31,9 @@ General Compute ~~~~~~~ +- Added ``ex_assign_public_ip`` to ``create_node`` in ec2 driver + [Kyle Long] + - Allow user to filter VPC by project in the CloudStack driver by passing ``project`` argument to the ``ex_list_vps`` method. (GITHUB-516) From 4ec2a05ca7808c3a6d671fba725c3f56cd89c360 Mon Sep 17 00:00:00 2001 From: Kyle Long Date: Wed, 30 Sep 2015 12:36:12 -0500 Subject: [PATCH 3/3] updating ips to be in TEST-NET-1 block https://tools.ietf.org/html/rfc5737 --- .../ec2/run_instances_with_subnet_and_security_group.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml b/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml index 5ebb5fdb6f..b43bea9f32 100644 --- a/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml +++ b/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml @@ -12,7 +12,7 @@ 0 pending - ip-192-168-79-96.us-east-1.compute.internal + ip-192-0-2-5.us-east-1.compute.internal 0 @@ -30,7 +30,7 @@ subnet-11111111 vpc-11111111 - 192.168.79.96 + 192.0.2.5 true @@ -58,7 +58,7 @@ 111111111111 in-use 06:ea:24:17:f7:77 - 192.168.79.96 + 192.0.2.5 true @@ -75,7 +75,7 @@ - 192.168.79.96 + 192.0.2.5 true