diff options
author | Mitch.Garnaat <Mitch.Garnaat@604d75c7-a419-0410-a38f-bde1a0bd1dbf> | 2009-12-14 17:24:40 +0000 |
---|---|---|
committer | Mitch.Garnaat <Mitch.Garnaat@604d75c7-a419-0410-a38f-bde1a0bd1dbf> | 2009-12-14 17:24:40 +0000 |
commit | c6951c5798a67557f489ef45648d9a522239e4b9 (patch) | |
tree | 7e51abdfd6b138193565a20f5fff666df46eb333 | |
parent | ba3544fc18d5c5e827b1c1777b7811201545a8c5 (diff) | |
download | boto-c6951c5798a67557f489ef45648d9a522239e4b9.tar.gz |
Initial support for Spot Instances. Still rough around the edges.
-rw-r--r-- | boto/ec2/blockdevicemapping.py | 4 | ||||
-rw-r--r-- | boto/ec2/connection.py | 270 | ||||
-rw-r--r-- | boto/ec2/instance.py | 6 | ||||
-rw-r--r-- | boto/ec2/launchspecification.py | 96 | ||||
-rw-r--r-- | boto/ec2/spotdatafeedsubscription.py | 54 | ||||
-rw-r--r-- | boto/ec2/spotinstancerequest.py | 84 | ||||
-rw-r--r-- | boto/ec2/spotpricehistory.py | 52 |
7 files changed, 552 insertions, 14 deletions
diff --git a/boto/ec2/blockdevicemapping.py b/boto/ec2/blockdevicemapping.py index e70fa9c6..ef7163a6 100644 --- a/boto/ec2/blockdevicemapping.py +++ b/boto/ec2/blockdevicemapping.py @@ -72,10 +72,10 @@ class BlockDeviceMapping(dict): elif name == 'item': self[self.current_name] = self.current_value - def build_list_params(self, params): + def build_list_params(self, params, prefix=''): i = 1 for dev_name in self: - pre = 'BlockDeviceMapping.%d' % i + pre = '%sBlockDeviceMapping.%d' % (pre, i) params['%s.DeviceName' % pre] = dev_name ebs = self[dev_name] if ebs.snapshot_id: diff --git a/boto/ec2/connection.py b/boto/ec2/connection.py index ae458639..3b102013 100644 --- a/boto/ec2/connection.py +++ b/boto/ec2/connection.py @@ -42,11 +42,15 @@ from boto.ec2.securitygroup import SecurityGroup from boto.ec2.regioninfo import RegionInfo from boto.ec2.instanceinfo import InstanceInfo from boto.ec2.reservedinstance import ReservedInstancesOffering, ReservedInstance +from boto.ec2.spotinstancerequest import SpotInstanceRequest +from boto.ec2.spotpricehistory import SpotPriceHistory +from boto.ec2.spotdatafeedsubscription import SpotDatafeedSubscription +from boto.ec2.launchspecification import LaunchSpecification from boto.exception import EC2ResponseError class EC2Connection(AWSQueryConnection): - APIVersion = boto.config.get('Boto', 'ec2_version', '2009-10-31') + APIVersion = boto.config.get('Boto', 'ec2_version', '2009-11-30') DefaultRegionName = boto.config.get('Boto', 'ec2_region_name', 'us-east-1') DefaultRegionEndpoint = boto.config.get('Boto', 'ec2_region_endpoint', 'ec2.amazonaws.com') @@ -65,9 +69,12 @@ class EC2Connection(AWSQueryConnection): if not region: region = RegionInfo(self, self.DefaultRegionName, self.DefaultRegionEndpoint) self.region = region - AWSQueryConnection.__init__(self, aws_access_key_id, aws_secret_access_key, - is_secure, port, proxy, proxy_port, proxy_user, proxy_pass, - self.region.endpoint, debug, https_connection_factory, path) + AWSQueryConnection.__init__(self, aws_access_key_id, + aws_secret_access_key, + is_secure, port, proxy, proxy_port, + proxy_user, proxy_pass, + self.region.endpoint, debug, + https_connection_factory, path) def get_params(self): """ @@ -132,8 +139,9 @@ class EC2Connection(AWSQueryConnection): def get_all_ramdisks(self, ramdisk_ids=None, owners=None): """ - Retrieve all the EC2 ramdisks available on your account. Simply filters the list returned - by get_all_images because EC2 does not provide a way to filter server-side. + Retrieve all the EC2 ramdisks available on your account. + Simply filters the list returned by get_all_images because + EC2 does not provide a way to filter server-side. :type ramdisk_ids: list :param ramdisk_ids: A list of strings with the image IDs wanted @@ -192,10 +200,10 @@ class EC2Connection(AWSQueryConnection): :type root_device_name: string :param root_device_name: The root device name (e.g. /dev/sdh) - :type block_device_mapping: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` - :param block_device_mapping: A BlockDeviceMapping data structure - describing the EBS volumes associated - with the Image. + :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` + :param block_device_map: A BlockDeviceMapping data structure + describing the EBS volumes associated + with the Image. :rtype: string :return: The new image id @@ -366,7 +374,8 @@ class EC2Connection(AWSQueryConnection): user_data=None, addressing_type=None, instance_type='m1.small', placement=None, kernel_id=None, ramdisk_id=None, - monitoring_enabled=False, subnet_id=None): + monitoring_enabled=False, subnet_id=None, + block_device_mapping=None): """ Runs an image on EC2. @@ -406,6 +415,11 @@ class EC2Connection(AWSQueryConnection): :type subnet_id: string :param subnet_id: The subnet ID within which to launch the instances for VPC. + :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` + :param block_device_map: A BlockDeviceMapping data structure + describing the EBS volumes associated + with the Image. + :rtype: Reservation :return: The :class:`boto.ec2.instance.Reservation` associated with the request for machines """ @@ -438,6 +452,8 @@ class EC2Connection(AWSQueryConnection): params['Monitoring.Enabled'] = 'true' if subnet_id: params['SubnetId'] = subnet_id + if block_device_map: + block_device_map.build_list_params(params) return self.get_object('RunInstances', params, Reservation, verb='POST') def terminate_instances(self, instance_ids=None): @@ -493,7 +509,7 @@ class EC2Connection(AWSQueryConnection): :type instance_id: string :param instance_id: The instance ID of a running instance on the cloud. - :rtype: L{boto.ec2.instance.ConsoleOutput} + :rtype: :class:`boto.ec2.instance.ConsoleOutput` :return: The console output as a ConsoleOutput object """ params = {} @@ -599,6 +615,236 @@ class EC2Connection(AWSQueryConnection): 'Attribute' : attribute} return self.get_status('ResetImageAttribute', params) + # Spot Instances + + def get_all_spot_instance_requests(self, request_ids=None): + """ + Retrieve all the spot instances requests associated with your account. + + @type request_ids: list + @param request_ids: A list of strings of spot instance request IDs + + @rtype: list + @return: A list of + :class:`boto.ec2.spotinstancerequest.SpotInstanceRequest` + """ + params = {} + if request_ids: + self.build_list_params(params, request_ids, 'SpotInstanceRequestId') + return self.get_list('DescribeSpotInstanceRequests', params, + [('item', SpotInstanceRequest)]) + + def get_spot_price_history(self, start_time=None, end_time=None, + instance_type=None, product_description=None): + """ + Retrieve the recent history of spot instances pricing. + + @type start_time: str + @param start_time: An indication of how far back to provide price + changes for. An ISO8601 DateTime string. + + @type end_time: str + @param end_time: An indication of how far forward to provide price + changes for. An ISO8601 DateTime string. + + @type instance_type: str + @param instance_type: Filter responses to a particular instance type. + + @type product_description: str + @param product_descripton: Filter responses to a particular platform. + Valid values are currently: Linux + + @rtype: list + @return: A list tuples containing price and timestamp. + """ + params = {} + if start_time: + params['StartTime'] = start_time + if end_time: + params['EndTime'] = end_time + if instance_type: + params['InstanceType'] = instance_type + if product_description: + params['ProductDescription'] = product_description + return self.get_list('DescribeSpotPriceHistory', params, [('item', SpotPriceHistory)]) + + def request_spot_instances(self, price, image_id, count=1, type=None, + valid_from=None, valid_until=None, + launch_group=None, availability_zone_group=None, + key_name=None, security_groups=None, + user_data=None, addressing_type=None, + instance_type='m1.small', placement=None, + kernel_id=None, ramdisk_id=None, + monitoring_enabled=False, subnet_id=None, + block_device_map=None): + """ + Request instances on the spot market at a particular price. + + :type price: str + :param price: The maximum price of your bid + + :type image_id: string + :param image_id: The ID of the image to run + + :type count: int + :param count: The of instances to requested + + :type type: str + :param type: Type of request. Can be 'one-time' or 'persistent'. + Default is one-time. + + :type valid_from: str + :param valid_from: Start date of the request. An ISO8601 time string. + + :type valid_until: str + :param valid_until: End date of the request. An ISO8601 time string. + + :type launch_group: str + :param launch_group: If supplied, all requests will be fulfilled + as a group. + + :type availability_zone_group: str + :param availability_zone_group: If supplied, all requests will be fulfilled + within a single availability zone. + + :type key_name: string + :param key_name: The name of the key pair with which to launch instances + + :type security_groups: list of strings + :param security_groups: The names of the security groups with which to associate instances + + :type user_data: string + :param user_data: The user data passed to the launched instances + + :type instance_type: string + :param instance_type: The type of instance to run (m1.small, m1.large, m1.xlarge) + + :type placement: string + :param placement: The availability zone in which to launch the instances + + :type kernel_id: string + :param kernel_id: The ID of the kernel with which to launch the instances + + :type ramdisk_id: string + :param ramdisk_id: The ID of the RAM disk with which to launch the instances + + :type monitoring_enabled: bool + :param monitoring_enabled: Enable CloudWatch monitoring on the instance. + + :type subnet_id: string + :param subnet_id: The subnet ID within which to launch the instances for VPC. + + :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` + :param block_device_map: A BlockDeviceMapping data structure + describing the EBS volumes associated + with the Image. + + :rtype: Reservation + :return: The :class:`boto.ec2.instance.Reservation` associated with the request for machines + """ + params = {'LaunchSpecification.ImageId':image_id, + 'SpotPrice' : price} + if count: + params['InstanceCount'] = count + if valid_from: + params['ValidFrom'] = valid_from + if valid_until: + params['ValidUntil'] = valid_until + if launch_group: + params['LaunchGroup'] = launch_group + if availability_zone_group: + params['AvailabilityZoneGroup'] = availability_zone_group + if key_name: + params['LaunchSpecification.KeyName'] = key_name + if security_groups: + l = [] + for group in security_groups: + if isinstance(group, SecurityGroup): + l.append(group.name) + else: + l.append(group) + self.build_list_params(params, l, + 'LaunchSpecification.SecurityGroup') + if user_data: + params['LaunchSpecification.UserData'] = base64.b64encode(user_data) + if addressing_type: + params['LaunchSpecification.AddressingType'] = addressing_type + if instance_type: + params['LaunchSpecification.InstanceType'] = instance_type + if placement: + params['LaunchSpecification.Placement.AvailabilityZone'] = placement + if kernel_id: + params['LaunchSpecification.KernelId'] = kernel_id + if ramdisk_id: + params['LaunchSpecification.RamdiskId'] = ramdisk_id + if monitoring_enabled: + params['LaunchSpecification.Monitoring.Enabled'] = 'true' + if subnet_id: + params['LaunchSpecification.SubnetId'] = subnet_id + if block_device_map: + block_device_map.build_list_params(params, 'LaunchSpecification.') + return self.get_list('RequestSpotInstances', params, + [('item', SpotInstanceRequest)], + verb='POST') + + + def cancel_spot_instance_requests(self, request_ids): + """ + Cancel the specified Spot Instance Requests. + + :type request_ids: list + :param request_ids: A list of strings of the Request IDs to terminate + + :rtype: list + :return: A list of the instances terminated + """ + params = {} + if request_ids: + self.build_list_params(params, request_ids, 'SpotInstanceRequestId') + return self.get_list('CancelSpotInstanceRequests', params, [('item', Instance)]) + + def get_spot_datafeed_subscription(self): + """ + Return the current spot instance data feed subscription + associated with this account, if any. + + :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription + :return: The datafeed subscription object or None + """ + return self.get_object('DescribeSpotDatafeedSubscription', + None, SpotDatafeedSubscription) + + def create_spot_datafeed_subscription(self, bucket, prefix=None): + """ + Create a spot instance datafeed subscription for this account. + + :type bucket: str or unicode + :param bucket: The name of the bucket where spot instance data + will be written. + + :type prefix: str or unicode + :param prefix: An optional prefix that will be pre-pended to all + data files written to the bucket. + + :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription + :return: The datafeed subscription object or None + """ + params = {'Bucket' : bucket} + if prefix: + params['Prefix'] = prefix + return self.get_object('CreateSpotDatafeedSubscription', + None, SpotDatafeedSubscription) + + def delete_spot_datafeed_subscription(self): + """ + Delete the current spot instance data feed subscription + associated with this account + + :rtype: bool + :return: True if successful + """ + return self.get_status('DeleteSpotDatafeedSubscription', None) + # Zone methods def get_all_zones(self, zones=None): diff --git a/boto/ec2/instance.py b/boto/ec2/instance.py index 08dfe87f..5932c4e7 100644 --- a/boto/ec2/instance.py +++ b/boto/ec2/instance.py @@ -87,6 +87,8 @@ class Instance(EC2Object): self.product_codes = ProductCodes() self.ami_launch_index = None self.monitored = False + self.instance_class = None + self.spot_instance_request_id = None self.subnet_id = None self.vpc_id = None self.private_ip_address = None @@ -157,6 +159,10 @@ class Instance(EC2Object): if value == 'enabled': self.monitored = True self._in_monitoring_element = False + elif name == 'instanceClass': + self.instance_class = value + elif name == 'spotInstanceRequestId': + self.spot_instance_request_id = value elif name == 'subnetId': self.subnet_id = value elif name == 'vpcId': diff --git a/boto/ec2/launchspecification.py b/boto/ec2/launchspecification.py new file mode 100644 index 00000000..a574a382 --- /dev/null +++ b/boto/ec2/launchspecification.py @@ -0,0 +1,96 @@ +# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, dis- +# tribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the fol- +# lowing conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +""" +Represents a launch specification for Spot instances. +""" + +from boto.ec2.ec2object import EC2Object +from boto.resultset import ResultSet +from boto.ec2.blockdevicemapping import BlockDeviceMapping +from boto.ec2.instance import Group + +class GroupList(list): + + def startElement(self, name, attrs, connection): + pass + + def endElement(self, name, value, connection): + if name == 'groupId': + self.append(value) + +class LaunchSpecification(EC2Object): + + def __init__(self, connection=None): + EC2Object.__init__(self, connection) + self.key_name = None + self.instance_type = None + self.image_id = None + self.groups = [] + self.placement = None + self.kernel = None + self.ramdisk = None + self.monitored = False + self.subnet_id = None + self._in_monitoring_element = False + self.block_device_mapping = None + + def __repr__(self): + return 'LaunchSpecification(%s)' % self.image_id + + def startElement(self, name, attrs, connection): + if name == 'groupSet': + self.groups = ResultSet([('item', Group)]) + return self.groups + elif name == 'monitoring': + self._in_monitoring_element = True + elif name == 'blockDeviceMapping': + self.block_device_mapping = BlockDeviceMapping() + return self.block_device_mapping + else: + return None + + def endElement(self, name, value, connection): + if name == 'imageId': + self.image_id = value + elif name == 'keyName': + self.key_name = value + elif name == 'instanceType': + self.instance_type = value + elif name == 'availabilityZone': + self.placement = value + elif name == 'placement': + pass + elif name == 'kernelId': + self.kernel = value + elif name == 'ramdiskId': + self.ramdisk = value + elif name == 'subnetId': + self.subnet_id = value + elif name == 'state': + if self._in_monitoring_element: + if value == 'enabled': + self.monitored = True + self._in_monitoring_element = False + else: + setattr(self, name, value) + + diff --git a/boto/ec2/spotdatafeedsubscription.py b/boto/ec2/spotdatafeedsubscription.py new file mode 100644 index 00000000..1434fc9d --- /dev/null +++ b/boto/ec2/spotdatafeedsubscription.py @@ -0,0 +1,54 @@ +# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, dis- +# tribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the fol- +# lowing conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +""" +Represents an EC2 Spot Instance Datafeed Subscription +""" +from boto.ec2.ec2object import EC2Object + +class SpotDatafeedSubscription(EC2Object): + + def __init__(self, connection=None, owner_id=None, + bucket=None, prefix=None, state=None): + EC2Object.__init__(self, connection) + self.owner_id = owner_id + self.bucket = bucket + self.prefix = prefix + self.state = state + + def __repr__(self): + return 'SpotDatafeedSubscription:%s' % self.bucket + + def endElement(self, name, value, connection): + if name == 'ownerId': + self.owner_id = value + elif name == 'bucket': + self.bucket = value + elif name == 'prefix': + self.prefix = value + elif name == 'state': + self.state = value + else: + setattr(self, name, value) + + def delete(self): + return self.connection.delete_spot_datafeed_subscription() + diff --git a/boto/ec2/spotinstancerequest.py b/boto/ec2/spotinstancerequest.py new file mode 100644 index 00000000..c24ac7bd --- /dev/null +++ b/boto/ec2/spotinstancerequest.py @@ -0,0 +1,84 @@ +# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, dis- +# tribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the fol- +# lowing conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +""" +Represents an EC2 Spot Instance Request +""" + +from boto.ec2.ec2object import EC2Object +from boto.ec2.launchspecification import LaunchSpecification + +class SpotInstanceRequest(EC2Object): + + def __init__(self, connection=None): + EC2Object.__init__(self, connection) + self.id = None + self.price = None + self.type = None + self.state = None + self.fault = None + self.valid_from = None + self.valid_until = None + self.launch_group = None + self.product_description = None + self.availability_zone_group = None + self.create_time = None + self.launch_specification = None + + def __repr__(self): + return 'SpotInstanceRequest:%s' % self.id + + def startElement(self, name, attrs, connection): + if name == 'launchSpecification': + self.launch_specification = LaunchSpecification(connection) + return self.launch_specification + else: + return None + + def endElement(self, name, value, connection): + if name == 'spotInstanceRequestId': + self.id = value + elif name == 'spotPrice': + self.price = float(value) + elif name == 'type': + self.type = value + elif name == 'state': + self.state = value + elif name == 'productDescription': + self.product_description = value + elif name == 'validFrom': + self.valid_from = value + elif name == 'validUntil': + self.valid_until = value + elif name == 'launchGroup': + self.launch_group = value + elif name == 'availabilityZoneGroup': + self.availability_zone_group = value + elif name == 'createTime': + self.create_time = value + else: + setattr(self, name, value) + + def cancel(self): + self.connection.cancel_spot_instance_requests([self.id]) + + + diff --git a/boto/ec2/spotpricehistory.py b/boto/ec2/spotpricehistory.py new file mode 100644 index 00000000..d4e17110 --- /dev/null +++ b/boto/ec2/spotpricehistory.py @@ -0,0 +1,52 @@ +# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, dis- +# tribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the fol- +# lowing conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +""" +Represents an EC2 Spot Instance Request +""" + +from boto.ec2.ec2object import EC2Object + +class SpotPriceHistory(EC2Object): + + def __init__(self, connection=None): + EC2Object.__init__(self, connection) + self.price = 0.0 + self.instance_type = None + self.product_description = None + self.timestamp = None + + def __repr__(self): + return 'SpotPriceHistory(%s):%2f' % (self.instance_type, self.price) + + def endElement(self, name, value, connection): + if name == 'instanceType': + self.instance_type = value + elif name == 'spotPrice': + self.price = float(value) + elif name == 'productDescription': + self.product_description = value + elif name == 'timestamp': + self.timestamp = value + else: + setattr(self, name, value) + + |