Repository: libcloud Updated Branches: refs/heads/trunk e82cbcdd1 -> 1ab649685
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). Closes #590 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/1de64d29 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/1de64d29 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/1de64d29 Branch: refs/heads/trunk Commit: 1de64d2922e11c913e490e28c769d4def85fa87c Parents: e82cbcd Author: Kyle Long <[email protected]> Authored: Wed Sep 30 11:56:10 2015 -0500 Committer: Tomaz Muraus <[email protected]> Committed: Fri Oct 2 20:56:48 2015 +0200 ---------------------------------------------------------------------- libcloud/compute/drivers/ec2.py | 42 +++++++++- ...instances_with_subnet_and_security_group.xml | 87 ++++++++++++++++++++ libcloud/test/compute/test_ec2.py | 31 +++++++ 3 files changed, 158 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/1de64d29/libcloud/compute/drivers/ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 9930f73..dfeee7c 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -2312,6 +2312,15 @@ class BaseEC2NodeDriver(NodeDriver): :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 @@ class BaseEC2NodeDriver(NodeDriver): ' 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 @@ class BaseEC2NodeDriver(NodeDriver): 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') http://git-wip-us.apache.org/repos/asf/libcloud/blob/1de64d29/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml ---------------------------------------------------------------------- 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 0000000..5ebb5fd --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/run_instances_with_subnet_and_security_group.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>ebfcb9e2-fe5f-4afd-ac91-6a9946305e32</requestId> + <reservationId>r-11111111</reservationId> + <ownerId>111111111111</ownerId> + <groupSet/> + <instancesSet> + <item> + <instanceId>i-11111111</instanceId> + <imageId>ami-11111111</imageId> + <instanceState> + <code>0</code> + <name>pending</name> + </instanceState> + <privateDnsName>ip-192-168-79-96.us-east-1.compute.internal</privateDnsName> + <dnsName/> + <reason/> + <amiLaunchIndex>0</amiLaunchIndex> + <productCodes/> + <instanceType>m3.medium</instanceType> + <launchTime>2015-09-30T14:37:59.000Z</launchTime> + <placement> + <availabilityZone>us-east-1a</availabilityZone> + <groupName/> + <tenancy>default</tenancy> + </placement> + <kernelId>aki-111111111</kernelId> + <monitoring> + <state>disabled</state> + </monitoring> + <subnetId>subnet-11111111</subnetId> + <vpcId>vpc-11111111</vpcId> + <privateIpAddress>192.168.79.96</privateIpAddress> + <sourceDestCheck>true</sourceDestCheck> + <groupSet> + <item> + <groupId>sg-11111111</groupId> + <groupName>test-security-group</groupName> + </item> + </groupSet> + <stateReason> + <code>pending</code> + <message>pending</message> + </stateReason> + <architecture>x86_64</architecture> + <rootDeviceType>ebs</rootDeviceType> + <rootDeviceName>/dev/sda</rootDeviceName> + <blockDeviceMapping/> + <virtualizationType>paravirtual</virtualizationType> + <clientToken/> + <hypervisor>xen</hypervisor> + <networkInterfaceSet> + <item> + <networkInterfaceId>eni-11111111</networkInterfaceId> + <subnetId>subnet-11111111</subnetId> + <vpcId>vpc-11111111</vpcId> + <description/> + <ownerId>111111111111</ownerId> + <status>in-use</status> + <macAddress>06:ea:24:17:f7:77</macAddress> + <privateIpAddress>192.168.79.96</privateIpAddress> + <sourceDestCheck>true</sourceDestCheck> + <groupSet> + <item> + <groupId>sg-11111111</groupId> + <groupName>test-security-group</groupName> + </item> + </groupSet> + <attachment> + <attachmentId>eni-attach-11111111</attachmentId> + <deviceIndex>0</deviceIndex> + <status>attaching</status> + <attachTime>2015-09-30T14:37:59.000Z</attachTime> + <deleteOnTermination>true</deleteOnTermination> + </attachment> + <privateIpAddressesSet> + <item> + <privateIpAddress>192.168.79.96</privateIpAddress> + <primary>true</primary> + </item> + </privateIpAddressesSet> + </item> + </networkInterfaceSet> + <ebsOptimized>false</ebsOptimized> + </item> + </instancesSet> +</RunInstancesResponse> http://git-wip-us.apache.org/repos/asf/libcloud/blob/1de64d29/libcloud/test/compute/test_ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 6a5cdeb..a1ff899 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -116,6 +116,26 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin): 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 @@ class EC2MockHttp(MockHttpTestCase): 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'})
