Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions libcloud/compute/drivers/ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
'EC2NodeLocation',
'EC2ReservedNode',
'EC2SecurityGroup',
'EC2PlacementGroup',
'EC2Network',
'EC2NetworkSubnet',
'EC2NetworkInterface',
Expand Down Expand Up @@ -1730,6 +1731,21 @@ def __repr__(self):
% (self.id, self.name))


class EC2PlacementGroup(object):
"""Represents information about a Placement Grous

Note: This class is EC2 specific.
"""
def __init__(self, name, state, strategy='cluster', extra=None):
self.name = name
self.strategy = strategy
self.extra = extra or {}

def __repr__(self):
return '<EC2PlacementGroup: name=%s, state=%s' % (self.name,
self.strategy)


class EC2Network(object):
"""
Represents information about a VPC (Virtual Private Cloud) network
Expand Down Expand Up @@ -2166,6 +2182,10 @@ def create_node(self, **kwargs):

:keyword ex_subnet: The subnet to launch the instance into.
:type ex_subnet: :class:`.EC2Subnet`

:keyword ex_placement_group: The placement group to launch
the instance into.
:type ex_placement_group: ``str``
"""
image = kwargs["image"]
size = kwargs["size"]
Expand Down Expand Up @@ -2254,6 +2274,9 @@ def create_node(self, **kwargs):
if 'ex_subnet' in kwargs:
params['SubnetId'] = kwargs['ex_subnet'].id

if 'ex_placement_group' in kwargs and kwargs['ex_placement_group']:
params['Placement.GroupName'] = kwargs['ex_placement_group']

object = self.connection.request(self.path, params=params).object
nodes = self._to_nodes(object, 'instancesSet/item')

Expand Down Expand Up @@ -2591,6 +2614,49 @@ def delete_image(self, image):
response = self.connection.request(self.path, params=params).object
return self._get_boolean(response)

def ex_create_placement_group(self, name):
"""Creates new Placement Group

:param name: Name for new placement Group
:type: ``str``

:rtype: ``bool``
"""
params = {'Action': 'CreatePlacementGroup',
'Strategy': 'cluster',
'GroupName': name}
response = self.connection.request(self.path, params=params).object
return self._get_boolean(response)

def ex_delete_placement_group(self, name):
"""Deletes Placement Group

:param name: Placement Group name
:type: ``str``

:rtype: ``bool``
"""
params = {'Action': 'DeletePlacementGroup',
'GroupName': name}
response = self.connection.request(self.path, params=params).object
return self._get_boolean(response)

def ex_list_placement_groups(self, names=()):
"""List Placement Groups

:param names: Placement Group names
:type: ``list`` of ``str``

:rtype: ``list`` of :class:`.EC2PlacementGroup`
"""
params = {'Action': 'DescribePlacementGroups'}

for n, name in enumerate(names, 1):
params['GroupName.%s' % n] = name

response = self.connection.request(self.path, params=params).object
return self._to_placement_groups(response)

def ex_register_image(self, name, description=None, architecture=None,
image_location=None, root_device_name=None,
block_device_mapping=None, kernel_id=None,
Expand Down Expand Up @@ -4832,6 +4898,24 @@ def _to_address(self, element, only_associated):

return ElasticIP(public_ip, domain, instance_id, extra=extra)

def _to_placement_groups(self, response):
return [self._to_placement_group(el)
for el in response.findall(
fixxpath(xpath='placementGroupSet/item',
namespace=NAMESPACE))]

def _to_placement_group(self, element):
name = findtext(element=element,
xpath='groupName',
namespace=NAMESPACE)
state = findtext(element=element,
xpath='state',
namespace=NAMESPACE)
strategy = findtext(element=element,
xpath='strategy',
namespace=NAMESPACE)
return EC2PlacementGroup(name, state, strategy)

def _to_subnets(self, response):
return [self._to_subnet(el) for el in response.findall(
fixxpath(xpath='subnetSet/item', namespace=NAMESPACE))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<CreatePlacementGroupResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>d4904fd9-82c2-4ea5-adfe-a9cc3EXAMPLE</requestId>
<return>true</return>
</CreatePlacementGroupResponse>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<DeletePlacementGroupResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>d4904fd9-82c2-4ea5-adfe-a9cc3EXAMPLE</requestId>
<return>true</return>
</DeletePlacementGroupResponse>
15 changes: 15 additions & 0 deletions libcloud/test/compute/fixtures/ec2/describe_placement_groups.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<DescribePlacementGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestID>d4904fd9-82c2-4ea5-adfe-a9cc3EXAMPLE</requestID>
<placementGroupSet>
<item>
<groupName>XYZ-cluster</groupName>
<strategy>cluster</strategy>
<state>available</state>
</item>
<item>
<groupName>XYZ-cluster2</groupName>
<strategy>cluster</strategy>
<state>available</state>
</item>
</placementGroupSet>
</DescribePlacementGroupsResponse>
29 changes: 29 additions & 0 deletions libcloud/test/compute/test_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from libcloud.compute.drivers.ec2 import EC2APNENodeDriver
from libcloud.compute.drivers.ec2 import EC2APSESydneyNodeDriver
from libcloud.compute.drivers.ec2 import EC2SAEastNodeDriver
from libcloud.compute.drivers.ec2 import EC2PlacementGroup
from libcloud.compute.drivers.ec2 import NimbusNodeDriver, EucNodeDriver
from libcloud.compute.drivers.ec2 import OutscaleSASNodeDriver
from libcloud.compute.drivers.ec2 import IdempotentParamError
Expand Down Expand Up @@ -928,6 +929,22 @@ def test_ex_create_security_group(self):

self.assertEqual(group["group_id"], "sg-52e2f530")

def test_ex_create_placement_groups(self):
resp = self.driver.ex_create_placement_group("NewPG")
self.assertTrue(resp)

def test_ex_delete_placement_groups(self):
pgs = self.driver.ex_list_placement_groups()
pg = pgs[0]

resp = self.driver.ex_delete_placement_group(pg.name)
self.assertTrue(resp)

def test_ex_list_placement_groups(self):
pgs = self.driver.ex_list_placement_groups()
self.assertEqual(len(pgs), 2)
self.assertIsInstance(pgs[0], EC2PlacementGroup)

def test_ex_list_networks(self):
vpcs = self.driver.ex_list_networks()

Expand Down Expand Up @@ -1494,6 +1511,18 @@ def _DetachInternetGateway(self, method, url, body, headers):
body = self.fixtures.load('detach_internet_gateway.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])

def _CreatePlacementGroup(self, method, url, body, headers):
body = self.fixtures.load('create_placement_groups.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])

def _DeletePlacementGroup(self, method, url, body, headers):
body = self.fixtures.load('delete_placement_groups.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])

def _DescribePlacementGroups(self, method, url, body, headers):
body = self.fixtures.load('describe_placement_groups.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])


class EucMockHttp(EC2MockHttp):
fixtures = ComputeFileFixtures('ec2')
Expand Down