I think that using availability zones in place of locations is a
reasonable solution, so I have attached a short patch which adds
availability zones to each region.

Thanks,
Tomaz

On Sat, Dec 11, 2010 at 12:26 AM, Paul Querna <[email protected]> wrote:

> AZs actually map pretty well to what list_locations should have
> available to you.
>
> For each region, we are currently hard coding a single Location:
>    def list_locations(self):
>        return [NodeLocation(0, 'Amazon US N. Virginia', 'US', self)]
>
> So I'd be fine with list_locations actually returning a list of the
> Availability Zones.
>
> I had some thought at one point of making an Aggregate EC2 Driver,
> which would connect to all regions and combine all operations across
> all regions, ie list_nodes, but this is kinda hard to be feasible for
> things like create_node which need Region specific parameters for
> things like what AMI to boot.  In that context a list_locations
> returning each region would of made sense, but for a practical matter,
> I think returning each AZ inside a region is a good change.
>
> Thanks,
>
> Paul
>
>
>
> On Fri, Dec 10, 2010 at 3:14 PM, Grig Gheorghiu
> <[email protected]> wrote:
> > Hello,
> >
> > I was looking for a way to launch EC2 instances via libcloud while
> > also specify an availability zone (AZ), such as us-east-1b or
> > us-east-1c for example. Libcloud supports the notion of EC2 location,
> > which is equivalent to an EC2 region from what I see, but there seems
> > to be no way of dealing with AZs. Or am I mistaken?
> >
> > Thanks,
> >
> > Grig
> >
>
From 8dc51a01129e221e79dea39f2bb4d30d70c0c172 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Toma=C5=BE=20Muraus?= <[email protected]>
Date: Sat, 11 Dec 2010 03:02:04 +0100
Subject: [PATCH] Add support for availability zones to EC2 driver.

---
 libcloud/drivers/ec2.py |   96 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 88 insertions(+), 8 deletions(-)

diff --git a/libcloud/drivers/ec2.py b/libcloud/drivers/ec2.py
index ccfa71f..baf4258 100644
--- a/libcloud/drivers/ec2.py
+++ b/libcloud/drivers/ec2.py
@@ -149,6 +149,17 @@ EC2_EU_WEST_INSTANCE_TYPES['m2.4xlarge']['price'] = '2.68'
 # prices are the same
 EC2_AP_SOUTHEAST_INSTANCE_TYPES = dict(EC2_EU_WEST_INSTANCE_TYPES)

+
+class EC2NodeLocation(NodeLocation):
+    def __init__(self, id, name, country, driver, availability_zone):
+        super(EC2NodeLocation, self).__init__(id, name, country, driver)
+        self.availability_zone = availability_zone
+
+    def __repr__(self):
+        return (('<EC2NodeLocation: id=%s, name=%s, country=%s, availability_zone=%s driver=%s>')
+                % (self.id, self.name, self.country, self.availability_zone.name,
+                   self.driver.name))
+
 class EC2Response(Response):
     """
     EC2 specific response parsing and error handling.
@@ -231,6 +242,21 @@ class EC2Connection(ConnectionUserAndKey):
         )
         return b64_hmac

+class ExEC2AvailabilityZone(object):
+    """
+    Extension class which stores information about an EC2 availability zone.
+
+    Note: This class is EC2 specific.
+    """
+    def __init__(self, name, zone_state, region_name):
+        self.name = name
+        self.zone_state = zone_state
+        self.region_name = region_name
+
+    def __repr__(self):
+        return (('<ExEC2AvailabilityZone: name=%s, zone_state=%s, region_name=%s>')
+                % (self.name, self.zone_state, self.region_name))
+
 class EC2NodeDriver(NodeDriver):
     """
     Amazon EC2 node driver
@@ -239,6 +265,9 @@ class EC2NodeDriver(NodeDriver):
     connectionCls = EC2Connection
     type = Provider.EC2
     name = 'Amazon EC2 (us-east-1)'
+    friendly_name = 'Amazon US N. Virginia'
+    country = 'US'
+    region_name = 'us-east-1'
     path = '/'

     _instance_types = EC2_US_EAST_INSTANCE_TYPES
@@ -359,6 +388,14 @@ class EC2NodeDriver(NodeDriver):
         )
         return images

+    def list_locations(self):
+        locations = []
+        for index, availability_zone in enumerate(self.ex_list_availability_zones()):
+            locations.append(EC2NodeLocation(index, self.friendly_name,
+                                             self.country, self, availability_zone))
+
+        return locations
+
     def ex_create_keypair(self, name):
         """Creates a new keypair

@@ -488,6 +525,41 @@ class EC2NodeDriver(NodeDriver):
                 raise e
         return results

+    def ex_list_availability_zones(self, only_available=True):
+        """
+        Return a list of L{ExEC2AvailabilityZone} objects for the current region.
+
+        Note: This is an extension method and is only available for EC2 driver.
+
+        @keyword    only_available: If true, return only availability zones with
+                                    state 'available'
+        @type       only_available: C{string}
+
+        """
+        params = {'Action': 'DescribeAvailabilityZones'}
+
+        if only_available:
+            params.update({'Filter.0.Name': 'state'})
+            params.update({'Filter.0.Value.0': 'available'})
+
+        params.update({'Filter.1.Name': 'region-name'})
+        params.update({'Filter.1.Value.0': self.region_name})
+
+        result = self.connection.request(self.path, params=params.copy()).object
+
+        availability_zones = []
+        for element in self._findall(result, 'availabilityZoneInfo/item'):
+            name = self._findtext(element, 'zoneName')
+            zone_state = self._findtext(element, 'zoneState')
+            region_name = self._findtext(element, 'regionName')
+
+            availability_zone = ExEC2AvailabilityZone(name = name,
+                                                      zone_state = zone_state,
+                                                      region_name = region_name)
+            availability_zones.append(availability_zone)
+
+        return availability_zones
+
     def create_node(self, **kwargs):
         """Create a new EC2 node

@@ -525,6 +597,13 @@ class EC2NodeDriver(NodeDriver):
             for sig in range(len(kwargs['ex_securitygroup'])):
                 params['SecurityGroup.%d' % (sig+1,)]  = kwargs['ex_securitygroup'][sig]

+        if 'location' in kwargs:
+            availability_zone = kwargs['location'].availability_zone
+            if availability_zone.region_name != self.region_name:
+                raise AttributeError('Invalid availability zone: %s' %
+                                                       (availability_zone.name))
+            params['Placement.AvailabilityZone'] = availability_zone.name
+
         if 'ex_keyname' in kwargs:
             params['KeyName'] = kwargs['ex_keyname']

@@ -557,8 +636,6 @@ class EC2NodeDriver(NodeDriver):
         res = self.connection.request(self.path, params=params).object
         return self._get_terminate_boolean(res)

-    def list_locations(self):
-        return [NodeLocation(0, 'Amazon US N. Virginia', 'US', self)]

 class EC2EUConnection(EC2Connection):
     """
@@ -572,10 +649,11 @@ class EC2EUNodeDriver(EC2NodeDriver):
     """

     name = 'Amazon EC2 (eu-west-1)'
+    friendly_name = 'Amazon Europe Ireland'
+    country = 'IE'
+    region_name = 'eu-west-1'
     connectionCls = EC2EUConnection
     _instance_types = EC2_EU_WEST_INSTANCE_TYPES
-    def list_locations(self):
-        return [NodeLocation(0, 'Amazon Europe Ireland', 'IE', self)]

 class EC2USWestConnection(EC2Connection):
     """
@@ -590,10 +668,11 @@ class EC2USWestNodeDriver(EC2NodeDriver):
     """

     name = 'Amazon EC2 (us-west-1)'
+    friendly_name = 'Amazon US N. California'
+    country = 'US'
+    region_name = 'us-west-1'
     connectionCls = EC2USWestConnection
     _instance_types = EC2_US_WEST_INSTANCE_TYPES
-    def list_locations(self):
-        return [NodeLocation(0, 'Amazon US N. California', 'US', self)]

 class EC2APSEConnection(EC2Connection):
     """
@@ -608,10 +687,11 @@ class EC2APSENodeDriver(EC2NodeDriver):
     """

     name = 'Amazon EC2 (ap-southeast-1)'
+    friendly_name = 'Amazon Asia-Pacific Singapore'
+    country = 'SG'
+    region_name = 'ap-southeast-1'
     connectionCls = EC2APSEConnection
     _instance_types = EC2_AP_SOUTHEAST_INSTANCE_TYPES
-    def list_locations(self):
-        return [NodeLocation(0, 'Amazon Asia-Pacific Singapore', 'SG', self)]

 class EucConnection(EC2Connection):
     """
--
1.7.3.3

Reply via email to