Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ec2 driver support for assigning a public ip #590

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -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)
Expand Down
42 changes: 40 additions & 2 deletions libcloud/compute/drivers/ec2.py
Expand Up @@ -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"]
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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')

Expand Down
@@ -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-0-2-5.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.0.2.5</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.0.2.5</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.0.2.5</privateIpAddress>
<primary>true</primary>
</item>
</privateIpAddressesSet>
</item>
</networkInterfaceSet>
<ebsOptimized>false</ebsOptimized>
</item>
</instancesSet>
</RunInstancesResponse>
31 changes: 31 additions & 0 deletions libcloud/test/compute/test_ec2.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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'})
Expand Down