Repository: libcloud
Updated Branches:
  refs/heads/trunk 5f0ccc1a5 -> f7025a95e


Add support for placement groups to the EC2 driver.

Closes #418

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/f7025a95
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/f7025a95
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/f7025a95

Branch: refs/heads/trunk
Commit: f7025a95ef18e85ad35967224c75bed71e85b21d
Parents: 5f0ccc1
Author: Mikhail Ovsyannikov <[email protected]>
Authored: Thu Dec 18 13:40:15 2014 +0300
Committer: Tomaz Muraus <[email protected]>
Committed: Sun Jan 4 19:03:49 2015 +0100

----------------------------------------------------------------------
 CHANGES.rst                                     |  4 +
 libcloud/compute/drivers/ec2.py                 | 89 ++++++++++++++++++++
 .../fixtures/ec2/create_placement_groups.xml    |  4 +
 .../fixtures/ec2/delete_placement_groups.xml    |  4 +
 .../fixtures/ec2/describe_placement_groups.xml  | 15 ++++
 libcloud/test/compute/test_ec2.py               | 29 +++++++
 6 files changed, 145 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 47a1ab6..80c0fd0 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -107,6 +107,10 @@ Compute
   (GITHUB-421)
   [ZuluPro]
 
+- Add support for placement group management to the EC2 driver.
+  (GITHUB-418)
+  [Mikhail Ovsyannikov]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index 32b578f..c070d79 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -65,6 +65,7 @@ __all__ = [
     'EC2NodeLocation',
     'EC2ReservedNode',
     'EC2SecurityGroup',
+    'EC2PlacementGroup',
     'EC2Network',
     'EC2NetworkSubnet',
     'EC2NetworkInterface',
@@ -1730,6 +1731,22 @@ class EC2SecurityGroup(object):
                 % (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
@@ -2166,6 +2183,10 @@ class BaseEC2NodeDriver(NodeDriver):
 
         :keyword    ex_subnet: The subnet to launch the instance into.
         :type       ex_subnet: :class:`.EC2Subnet`
+
+        :keyword    ex_placement_group: The name of the placement group to
+                                        launch the instance into.
+        :type       ex_placement_group: ``str``
         """
         image = kwargs["image"]
         size = kwargs["size"]
@@ -2254,6 +2275,9 @@ class BaseEC2NodeDriver(NodeDriver):
         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')
 
@@ -2591,6 +2615,53 @@ class BaseEC2NodeDriver(NodeDriver):
         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 name: ``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 name: ``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=None):
+        """
+        List Placement Groups
+
+        :param names: Placement Group names
+        :type names: ``list`` of ``str``
+
+        :rtype: ``list`` of :class:`.EC2PlacementGroup`
+        """
+        names = names or []
+        params = {'Action': 'DescribePlacementGroups'}
+
+        for index, name in enumerate(names):
+            params['GroupName.%s' % index + 1] = 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,
@@ -4832,6 +4903,24 @@ class BaseEC2NodeDriver(NodeDriver):
 
         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))

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/libcloud/test/compute/fixtures/ec2/create_placement_groups.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/ec2/create_placement_groups.xml 
b/libcloud/test/compute/fixtures/ec2/create_placement_groups.xml
new file mode 100644
index 0000000..ca83b7f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/ec2/create_placement_groups.xml
@@ -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>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/libcloud/test/compute/fixtures/ec2/delete_placement_groups.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/ec2/delete_placement_groups.xml 
b/libcloud/test/compute/fixtures/ec2/delete_placement_groups.xml
new file mode 100644
index 0000000..69091a3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/ec2/delete_placement_groups.xml
@@ -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>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/libcloud/test/compute/fixtures/ec2/describe_placement_groups.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/ec2/describe_placement_groups.xml 
b/libcloud/test/compute/fixtures/ec2/describe_placement_groups.xml
new file mode 100644
index 0000000..787eb67
--- /dev/null
+++ b/libcloud/test/compute/fixtures/ec2/describe_placement_groups.xml
@@ -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>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f7025a95/libcloud/test/compute/test_ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_ec2.py 
b/libcloud/test/compute/test_ec2.py
index ce84912..e156565 100644
--- a/libcloud/test/compute/test_ec2.py
+++ b/libcloud/test/compute/test_ec2.py
@@ -29,6 +29,7 @@ from libcloud.compute.drivers.ec2 import EC2APSENodeDriver
 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
@@ -928,6 +929,22 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
 
         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()
 
@@ -1494,6 +1511,18 @@ class EC2MockHttp(MockHttpTestCase):
         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')

Reply via email to