You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2013/12/23 19:20:31 UTC
[2/5] git commit: Issue LIBCLOUD-469: Add Reserved Instance support
to EC2 driver.
Issue LIBCLOUD-469: Add Reserved Instance support to EC2 driver.
Signed-off-by: Tomaz Muraus <to...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c1d86602
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c1d86602
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c1d86602
Branch: refs/heads/trunk
Commit: c1d8660217794fc2dd545d83bf2b46f7300a3368
Parents: 7c72c2f
Author: Chris DeRamus <ch...@divvycloud.com>
Authored: Sun Dec 22 09:57:48 2013 -0500
Committer: Tomaz Muraus <to...@apache.org>
Committed: Mon Dec 23 19:04:06 2013 +0100
----------------------------------------------------------------------
libcloud/compute/drivers/ec2.py | 116 +++++++++++++++++++
.../ec2/describe_reserved_instances.xml | 21 ++++
libcloud/test/compute/test_ec2.py | 20 ++++
3 files changed, 157 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c1d86602/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index a1235d4..e4387fe 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -559,6 +559,28 @@ class ExEC2AvailabilityZone(object):
% (self.name, self.zone_state, self.region_name))
+class EC2ReservedNode(Node):
+ """
+ Class which stores information about EC2 reserved instances/nodes
+ Inherits from Node and passes in None for name and private/public IPs
+
+ Note: This class is EC2 specific.
+ """
+
+ def __init__(self, id, name, state, public_ips, private_ips,
+ driver, size=None, image=None, extra=None):
+ self.id = str(id) if id else None
+ self.name = name
+ self.state = state
+ self.public_ips = public_ips
+ self.private_ips = private_ips
+ self.driver = driver
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return (('<EC2ReservedNode: id=%s>') % (self.id))
+
+
class BaseEC2NodeDriver(NodeDriver):
"""
Base Amazon EC2 node driver.
@@ -608,6 +630,84 @@ class BaseEC2NodeDriver(NodeDriver):
for term_status
in ('shutting-down', 'terminated')])
+ def _to_reserved_nodes(self, object, xpath):
+ return [self._to_reserved_node(el)
+ for el in object.findall(fixxpath(xpath=xpath,
+ namespace=NAMESPACE))]
+
+ def _to_reserved_node(self, element):
+ """
+ Build an EC2ReservedNode object using the reserved instance properties.
+ Information on these properties can be found at http://goo.gl/ulXCC7.
+ """
+ # Build our extra attributes map
+ extra_attributes_map = {
+ 'instance_type': {
+ 'xpath': 'instanceType',
+ 'type': str
+ },
+ 'availability': {
+ 'xpath': 'availabilityZone',
+ 'type': str
+ },
+ 'start': {
+ 'xpath': 'start',
+ 'type': str
+ },
+ 'duration': {
+ 'xpath': 'duration',
+ 'type': int
+ },
+ 'usage_price': {
+ 'xpath': 'usagePrice',
+ 'type': float
+ },
+ 'fixed_price': {
+ 'xpath': 'fixedPrice',
+ 'type': float
+ },
+ 'instance_count': {
+ 'xpath': 'instanceCount',
+ 'type': int
+ },
+ 'description': {
+ 'xpath': 'productDescription',
+ 'type': str
+ },
+ 'instance_tenancy': {
+ 'xpath': 'instanceTenancy',
+ 'type': str
+ },
+ 'currency_code': {
+ 'xpath': 'currencyCode',
+ 'type': str
+ },
+ 'offering_type': {
+ 'xpath': 'offeringType',
+ 'type': str
+ }
+ }
+
+ # Define and build our extra dictionary
+ extra = {}
+ for attribute, values in extra_attributes_map.items():
+ type_func = values['type']
+ value = findattr(element=element, xpath=values['xpath'],
+ namespace=NAMESPACE)
+ extra[attribute] = type_func(value)
+
+ return EC2ReservedNode(id=findtext(element=element,
+ xpath='reservedInstancesId',
+ namespace=NAMESPACE),
+ name=None,
+ state=findattr(element=element,
+ xpath='state',
+ namespace=NAMESPACE),
+ public_ips=None,
+ private_ips=None,
+ driver=self,
+ extra=extra)
+
def _to_nodes(self, object, xpath, groups=None):
return [self._to_node(el, groups=groups)
for el in object.findall(fixxpath(xpath=xpath,
@@ -776,6 +876,22 @@ class BaseEC2NodeDriver(NodeDriver):
'description': description,
'state': state})
+ def list_reserved_nodes(self):
+ """
+ List all reserved instances/nodes which can be purchased from Amazon
+ for one or three year terms. Reservations are made at a region level
+ and reduce the hourly charge for instances.
+
+ More information can be found at http://goo.gl/ulXCC7.
+
+ :rtype: ``list`` of :class:`ExEC2ReservedNode`
+ """
+ params = {'Action': 'DescribeReservedInstances'}
+
+ response = self.connection.request(self.path, params=params).object
+
+ return self._to_reserved_nodes(response, 'reservedInstancesSet/item')
+
def list_nodes(self, ex_node_ids=None):
"""
List all nodes
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c1d86602/libcloud/test/compute/fixtures/ec2/describe_reserved_instances.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/ec2/describe_reserved_instances.xml b/libcloud/test/compute/fixtures/ec2/describe_reserved_instances.xml
new file mode 100644
index 0000000..15e14e3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/ec2/describe_reserved_instances.xml
@@ -0,0 +1,21 @@
+<DescribeReservedInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>56d0fffa-8819-4658-bdd7-548f143a86d2</requestId>
+ <reservedInstancesSet>
+ <item>
+ <reservedInstancesId>93bbbca2-c500-49d0-9ede-9d8737400498</reservedInstancesId>
+ <instanceType>t1.micro</instanceType>
+ <availabilityZone>us-east-1b</availabilityZone>
+ <start>2013-06-18T12:07:53.161Z</start>
+ <duration>31536000</duration>
+ <fixedPrice>23.0</fixedPrice>
+ <usagePrice>0.012</usagePrice>
+ <instanceCount>1</instanceCount>
+ <productDescription>Linux/UNIX</productDescription>
+ <state>active</state>
+ <instanceTenancy>default</instanceTenancy>
+ <currencyCode>USD</currencyCode>
+ <offeringType>Light Utilization</offeringType>
+ <recurringCharges/>
+ </item>
+ </reservedInstancesSet>
+</DescribeReservedInstancesResponse>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c1d86602/libcloud/test/compute/test_ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py
index bdd7a61..0222d08 100644
--- a/libcloud/test/compute/test_ec2.py
+++ b/libcloud/test/compute/test_ec2.py
@@ -843,6 +843,10 @@ class EC2MockHttp(MockHttpTestCase):
body = self.fixtures.load('describe_instances_with_tags.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+ def _DescribeReservedInstances(self, method, url, body, headers):
+ body = self.fixtures.load('describe_reserved_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])
@@ -1105,6 +1109,22 @@ class NimbusTests(EC2Tests):
self.assertTrue('m1.large' in ids)
self.assertTrue('m1.xlarge' in ids)
+ def test_list_reserved_nodes(self):
+ node = self.driver.list_reserved_nodes()[0]
+ self.assertEqual(node.id, '93bbbca2-c500-49d0-9ede-9d8737400498')
+ self.assertEqual(node.state, 'active')
+ self.assertEqual(node.extra['instance_type'], 't1.micro')
+ self.assertEqual(node.extra['availability'], 'us-east-1b')
+ self.assertEqual(node.extra['start'], '2013-06-18T12:07:53.161Z')
+ self.assertEqual(node.extra['duration'], 31536000)
+ self.assertEqual(node.extra['usage_price'], 0.012)
+ self.assertEqual(node.extra['fixed_price'], 23.0)
+ self.assertEqual(node.extra['instance_count'], 1)
+ self.assertEqual(node.extra['description'], 'Linux/UNIX')
+ self.assertEqual(node.extra['instance_tenancy'], 'default')
+ self.assertEqual(node.extra['currency_code'], 'USD')
+ self.assertEqual(node.extra['offering_type'], 'Light Utilization')
+
def test_list_nodes(self):
# overridden from EC2Tests -- Nimbus doesn't support elastic IPs.
node = self.driver.list_nodes()[0]