You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by je...@apache.org on 2011/01/03 06:14:25 UTC
svn commit: r1054527 - in /incubator/libcloud/trunk: CHANGES
libcloud/drivers/ec2.py test/test_ec2.py
Author: jerry
Date: Mon Jan 3 05:14:24 2011
New Revision: 1054527
URL: http://svn.apache.org/viewvc?rev=1054527&view=rev
Log:
Add support for availability zones to EC2 driver,
via ex_list_availability_zones; LIBCLOUD-67
Submitted By: Tomaž Muraus <ka...@k5-storitve.net>
Modified:
incubator/libcloud/trunk/CHANGES
incubator/libcloud/trunk/libcloud/drivers/ec2.py
incubator/libcloud/trunk/test/test_ec2.py
Modified: incubator/libcloud/trunk/CHANGES
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/CHANGES?rev=1054527&r1=1054526&r2=1054527&view=diff
==============================================================================
--- incubator/libcloud/trunk/CHANGES (original)
+++ incubator/libcloud/trunk/CHANGES Mon Jan 3 05:14:24 2011
@@ -2,6 +2,10 @@
Changes with Apache Libcloud 0.4.1 [In Development]
+ *) EC2 Driver availability zones, via ex_list_availability_zones;
+ list_locations rewrite to include availablity zones
+ [Tomaž Muraus]
+
*) EC2 Driver Idempotency capability in create_node; LIBCLOUD-69
[David LaBissoniere]
Modified: incubator/libcloud/trunk/libcloud/drivers/ec2.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/ec2.py?rev=1054527&r1=1054526&r2=1054527&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/ec2.py (original)
+++ incubator/libcloud/trunk/libcloud/drivers/ec2.py Mon Jan 3 05:14:24 2011
@@ -149,6 +149,18 @@ EC2_EU_WEST_INSTANCE_TYPES['m2.4xlarge']
# 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 +243,22 @@ 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 +267,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
@@ -360,24 +391,37 @@ 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
- @note: This is a non-standard extension API, and only works for EC2.
+ @note: This is a non-standard extension API, and
+ only works for EC2.
@type name: C{str}
- @param name: The name of the keypair to Create. This must be unique,
- otherwise an InvalidKeyPair.Duplicate exception is raised.
+ @param name: The name of the keypair to Create. This must be
+ unique, otherwise an InvalidKeyPair.Duplicate
+ exception is raised.
"""
- params = {'Action': 'CreateKeyPair',
- 'KeyName': name,
+ params = {
+ 'Action': 'CreateKeyPair',
+ 'KeyName': name,
}
response = self.connection.request(self.path, params=params).object
key_material = self._findtext(response, 'keyMaterial')
key_fingerprint = self._findtext(response, 'keyFingerprint')
return {
- 'keyMaterial': key_material,
- 'keyFingerprint': key_fingerprint,
+ 'keyMaterial': key_material,
+ 'keyFingerprint': key_fingerprint,
}
def ex_import_keypair(self, name, keyfile):
@@ -489,6 +533,45 @@ 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
@@ -529,6 +612,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']
@@ -564,8 +654,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):
"""
@@ -579,10 +667,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):
"""
@@ -597,10 +686,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):
"""
@@ -615,10 +705,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):
"""
Modified: incubator/libcloud/trunk/test/test_ec2.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/test_ec2.py?rev=1054527&r1=1054526&r2=1054527&view=diff
==============================================================================
--- incubator/libcloud/trunk/test/test_ec2.py (original)
+++ incubator/libcloud/trunk/test/test_ec2.py Mon Jan 3 05:14:24 2011
@@ -46,6 +46,11 @@ class EC2Tests(unittest.TestCase, TestCa
node = self.driver.list_nodes()[0]
self.assertEqual(node.id, 'i-4382922a')
+ def test_list_location(self):
+ locations = self.driver.list_locations()
+ self.assertTrue(len(locations) > 0)
+ self.assertTrue(locations[0].availability_zone != None)
+
def test_reboot_node(self):
node = Node('i-4382922a', None, None, None, None, self.driver)
ret = self.driver.reboot_node(node)
@@ -78,6 +83,14 @@ class EC2Tests(unittest.TestCase, TestCa
self.assertEqual(image.name, 'ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml')
self.assertEqual(image.id, 'ami-be3adfd7')
+ def test_ex_list_availability_zones(self):
+ availability_zones = self.driver.ex_list_availability_zones()
+ availability_zone = availability_zones[0]
+ self.assertTrue(len(availability_zones) > 0)
+ self.assertEqual(availability_zone.name, 'eu-west-1a')
+ self.assertEqual(availability_zone.zone_state, 'available')
+ self.assertEqual(availability_zone.region_name, 'eu-west-1')
+
class EC2MockHttp(MockHttp):
fixtures = FileFixtures('ec2')
@@ -86,6 +99,10 @@ class EC2MockHttp(MockHttp):
body = self.fixtures.load('describe_instances.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+ def _DescribeAvailabilityZones(self, method, url, body, headers):
+ body = self.fixtures.load('describe_availability_zones.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
def _RebootInstances(self, method, url, body, headers):
body = self.fixtures.load('reboot_instances.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])