1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

[compute|aws] add request level support for spot instances

closes #334
This commit is contained in:
geemus 2011-06-27 17:45:37 -07:00
parent 50cbeea302
commit b50b62d7bc
15 changed files with 594 additions and 1 deletions

View file

@ -30,17 +30,20 @@ module Fog
request :associate_address
request :attach_volume
request :authorize_security_group_ingress
request :cancel_spot_instance_requests
request :create_image
request :create_key_pair
request :create_placement_group
request :create_security_group
request :create_snapshot
request :create_spot_datafeed_subscription
request :create_tags
request :create_volume
request :delete_key_pair
request :delete_security_group
request :delete_placement_group
request :delete_snapshot
request :delete_spot_datafeed_subscription
request :delete_tags
request :delete_volume
request :deregister_image
@ -55,6 +58,9 @@ module Fog
request :describe_reserved_instances_offerings
request :describe_security_groups
request :describe_snapshots
request :describe_spot_datafeed_subscription
request :describe_spot_instance_requests
request :describe_spot_price_history
request :describe_tags
request :describe_volumes
request :detach_volume
@ -67,6 +73,7 @@ module Fog
request :reboot_instances
request :release_address
request :register_image
request :request_spot_instances
request :revoke_security_group_ingress
request :run_instances
request :terminate_instances
@ -252,7 +259,7 @@ module Fog
:host => @host,
:path => @path,
:port => @port,
:version => '2010-08-31'
:version => '2011-05-15'
}
)

View file

@ -0,0 +1,30 @@
module Fog
module Parsers
module Compute
module AWS
class CancelSpotInstanceRequests < Fog::Parsers::Base
def reset
@spot_instance_request = {}
@response = { 'spotInstanceRequestSet' => [] }
end
def end_element(name)
case name
when 'item'
@response['spotInstanceRequestSet'] << @spot_instance_request
@spot_instance_request = {}
when 'requestId'
@response[name] = value
when 'spotInstanceRequestId', 'state'
@spot_instance_request[name] = value
end
end
end
end
end
end
end

View file

@ -0,0 +1,34 @@
module Fog
module Parsers
module Compute
module AWS
class DescribeSpotPriceHistory < Fog::Parsers::Base
def reset
@spot_price = {}
@response = { 'spotPriceHistorySet' => [] }
end
def end_element(name)
case name
when 'availabilityZone', 'instanceType', 'productDescription'
@spot_price[name] = value
when 'item'
@response['spotPriceHistorySet'] << @spot_price
@spot_price = {}
when 'requestId'
@response[name] = value
when 'spotPrice'
@spot_price[name] = value.to_f
when 'timestamp'
@spot_price[name] = Time.parse(value)
end
end
end
end
end
end
end

View file

@ -0,0 +1,29 @@
module Fog
module Parsers
module Compute
module AWS
class SpotDatafeedSubscription < Fog::Parsers::Base
def reset
@response = { 'spotDatafeedSubscription' => {} }
end
def end_element(name)
case name
when 'bucket', 'ownerId', 'prefix', 'state'
@response['spotDatafeedSubscription'][name] = value
when 'code', 'message'
@response['spotDatafeedSubscription']['fault'] ||= {}
@response['spotDatafeedSubscription'][name] = value
when 'requestId'
@response[name] = value
end
end
end
end
end
end
end

View file

@ -0,0 +1,67 @@
module Fog
module Parsers
module Compute
module AWS
class SpotInstanceRequests < Fog::Parsers::Base
def reset
@block_device_mapping = []
@context = []
@contexts = ['blockDeviceMapping', 'groupSet']
@spot_instance_request = { 'launchSpecification' => { 'blockDeviceMapping' => [], 'groupSet' => [] } }
@response = { 'spotInstanceRequestSet' => [] }
end
def start_element(name, attrs = [])
super
if @contexts.include?(name)
@context.push(name)
end
end
def end_element(name)
case name
when 'attachTime'
@block_device_mapping[name] = Time.parse(value)
when *@contexts
@context.pop
when 'code', 'message'
@spot_instance_request['fault'] ||= {}
@spot_instance_request['fault'][name] = value
when 'createTime'
@spot_instance_request[name] = Time.parse(value)
when 'deleteOnTermination'
@block_device_mapping[name] = (value == 'true')
when 'deviceName', 'status', 'volumeId'
@block_device_mapping[name] = value
when 'groupId'
@spot_instance_request['launchSpecification']['groupSet'] << value
when 'instanceId', 'launchedAvailabilityZone', 'productDescription', 'spotInstanceRequestId', 'state', 'type'
@spot_instance_request[name] = value
when 'item'
case @context.last
when 'blockDeviceMapping'
@instance['blockDeviceMapping'] << @block_device_mapping
@block_device_mapping = {}
when nil
@response['spotInstanceRequestSet'] << @spot_instance_request
@spot_instance_request = { 'launchSpecification' => { 'blockDeviceMapping' => [], 'groupSet' => [] } }
end
when 'imageId', 'instanceType', 'keyname'
@spot_instance_request['launchSpecification'][name] = value
when 'enabled'
@spot_instance_request['launchSpecification']['monitoring'] = (value == 'true')
when 'requestId'
@response[name] = value
when 'spotPrice'
@spot_instance_request[name] = value.to_f
end
end
end
end
end
end
end

View file

@ -0,0 +1,34 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/cancel_spot_instance_requests'
# Terminate specified spot instance requests
#
# ==== Parameters
# * spot_instance_request_id<~Array> - Ids of instances to terminates
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> id of request
# * 'spotInstanceRequestSet'<~Array>:
# * 'spotInstanceRequestId'<~String> - id of cancelled spot instance
# * 'state'<~String> - state of cancelled spot instance
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CancelSpotInstanceRequests.html]
def cancel_spot_instance_requests(spot_instance_request_id)
params = Fog::AWS.indexed_param('SpotInstanceRequestId', spot_instance_request_id)
request({
'Action' => 'CancelSpotInstanceRequests',
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::CancelSpotInstanceRequests.new
}.merge!(params))
end
end
end
end
end

View file

@ -0,0 +1,41 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/spot_datafeed_subscription'
# Create a spot datafeed subscription
#
# ==== Parameters
# * bucket<~String> - bucket name to store datafeed in
# * prefix<~String> - prefix to store data with
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> - Id of request
# * 'spotDatafeedSubscription'<~Hash>:
# * 'bucket'<~String> - S3 bucket where data is stored
# * 'fault'<~Hash>:
# * 'code'<~String> - fault code
# * 'reason'<~String> - fault reason
# * 'ownerId'<~String> - AWS id of account owner
# * 'prefix'<~String> - prefix for datafeed items
# * 'state'<~String> - state of datafeed subscription
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateSpotDatafeedSubscription.html]
def create_spot_datafeed_subscription(bucket, prefix)
request(
'Action' => 'CreateSpotDatafeedSubscription',
'Bucket' => bucket,
'Prefix' => prefix,
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::SpotDatafeedSubscription.new
)
end
end
end
end
end

View file

@ -0,0 +1,28 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/basic'
# Delete a spot datafeed subscription
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> id of request
# * 'return'<~Boolean> - success?
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteSpotDatafeedSubscription.html]
def delete_spot_datafeed_subscription
request(
'Action' => 'DeleteSpotDatafeedSubscription',
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::Basic.new
)
end
end
end
end
end

View file

@ -0,0 +1,35 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/spot_datafeed_subscription'
# Describe spot datafeed subscription
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> - Id of request
# * 'spotDatafeedSubscription'<~Hash>:
# * 'bucket'<~String> - S3 bucket where data is stored
# * 'fault'<~Hash>:
# * 'code'<~String> - fault code
# * 'reason'<~String> - fault reason
# * 'ownerId'<~String> - AWS id of account owner
# * 'prefix'<~String> - prefix for datafeed items
# * 'state'<~String> - state of datafeed subscription
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotDatafeedSubscription.html]
def describe_spot_datafeed_subscription
request({
'Action' => 'DescribeSpotDatafeedSubscription',
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::SpotDatafeedSubscription.new
})
end
end
end
end
end

View file

@ -0,0 +1,47 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/spot_instance_requests'
# Describe all or specified spot instance requests
#
# ==== Parameters
# * filters<~Hash> - List of filters to limit results with
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> - Id of request
# * 'spotInstanceRequestSet'<~Array>:
# * 'createTime'<~Time> - time of instance request creation
# * 'instanceId'<~String> - instance id if one has been launched to fulfill request
# * 'launchedAvailabilityZone'<~String> - availability zone of instance if one has been launched to fulfill request
# * 'launchSpecification'<~Hash>:
# * 'blockDeviceMapping'<~Hash> - list of block device mappings for instance
# * 'groupSet'<~String> - security group(s) for instance
# * 'keyName'<~String> - keypair name for instance
# * 'imageId'<~String> - AMI for instance
# * 'instanceType'<~String> - type for instance
# * 'monitoring'<~Boolean> - monitoring status for instance
# * 'productDescription'<~String> - general description of AMI
# * 'spotInstanceRequestId'<~String> - id of spot instance request
# * 'spotPrice'<~Float> - maximum price for instances to be launched
# * 'state'<~String> - spot instance request state
# * 'type'<~String> - spot instance request type
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html]
def describe_spot_instance_requests(filters = {})
params = Fog::AWS.indexed_filters(filters)
request({
'Action' => 'DescribeSpotInstanceRequests',
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::SpotInstanceRequests.new
}.merge!(params))
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/describe_spot_price_history'
# Describe all or specified spot price history
#
# ==== Parameters
# * filters<~Hash> - List of filters to limit results with
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> - Id of request
# * 'spotPriceHistorySet'<~Array>:
# * 'availabilityZone'<~String> - availability zone for instance
# * 'instanceType'<~String> - the type of instance
# * 'productDescription'<~String> - general description of AMI
# * 'spotPrice'<~Float> - maximum price to launch one or more instances
# * 'timestamp'<~Time> - date and time of request creation
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotPriceHistory.html]
def describe_spot_price_history(filters = {})
params = Fog::AWS.indexed_filters(filters)
request({
'Action' => 'DescribeSpotPriceHistory',
:idempotent => true,
:parser => Fog::Parsers::Compute::AWS::DescribeSpotPriceHistory.new
}.merge!(params))
end
end
end
end
end

View file

@ -0,0 +1,83 @@
module Fog
module Compute
class AWS
class Real
require 'fog/compute/parsers/aws/spot_instance_requests'
# Launch specified instances
#
# ==== Parameters
# * 'image_id'<~String> - Id of machine image to load on instances
# * 'instance_type'<~String> - Type of instance
# * 'spot_price'<~Float> - maximum hourly price for instances launched
# * options<~Hash>:
# * 'AvailabilityZoneGroup'<~String> - specify whether or not to launch all instances in the same availability group
# * 'InstanceCount'<~Integer> - maximum number of instances to launch
# * 'LaunchGroup'<~String> - whether or not to launch/shutdown instances as a group
# * 'LaunchSpecification.BlockDeviceMapping'<~Array>: array of hashes
# * 'DeviceName'<~String> - where the volume will be exposed to instance
# * 'VirtualName'<~String> - volume virtual device name
# * 'Ebs.SnapshotId'<~String> - id of snapshot to boot volume from
# * 'Ebs.NoDevice'<~String> - specifies that no device should be mapped
# * 'Ebs.VolumeSize'<~String> - size of volume in GiBs required unless snapshot is specified
# * 'Ebs.DeleteOnTermination'<~String> - specifies whether or not to delete the volume on instance termination
# * 'LaunchSpecification.KeyName'<~String> - Name of a keypair to add to booting instances
# * 'LaunchSpecification.Monitoring.Enabled'<~Boolean> - Enables monitoring, defaults to disabled
# * 'LaunchSpecification.Placement.AvailabilityZone'<~String> - Placement constraint for instances
# * 'LaunchSpecification.SecurityGroup'<~Array> or <~String> - Name of security group(s) for instances
# * 'LaunchSpecification.UserData'<~String> - Additional data to provide to booting instances
# * 'Type'<~String> - spot instance request type in ['one-time', 'persistent']
# * 'ValidFrom'<~Time> - start date for request
# * 'ValidUntil'<~Time> - end date for request
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'requestId'<~String> - Id of request
# * 'spotInstanceRequestSet'<~Array>:
# * 'createTime'<~Time> - time of instance request creation
# * 'instanceId'<~String> - instance id if one has been launched to fulfill request
# * 'launchedAvailabilityZone'<~String> - availability zone of instance if one has been launched to fulfill request
# * 'launchSpecification'<~Hash>:
# * 'blockDeviceMapping'<~Hash> - list of block device mappings for instance
# * 'groupSet'<~String> - security group(s) for instance
# * 'keyName'<~String> - keypair name for instance
# * 'imageId'<~String> - AMI for instance
# * 'instanceType'<~String> - type for instance
# * 'monitoring'<~Boolean> - monitoring status for instance
# * 'productDescription'<~String> - general description of AMI
# * 'spotInstanceRequestId'<~String> - id of spot instance request
# * 'spotPrice'<~Float> - maximum price for instances to be launched
# * 'state'<~String> - spot instance request state
# * 'type'<~String> - spot instance request type
#
# {Amazon API Reference}[http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RequestSpotInstances.html]
def request_spot_instances(image_id, instance_type, spot_price, options = {})
if block_device_mapping = options.delete('LaunchSpecification.BlockDeviceMapping')
block_device_mapping.each_with_index do |mapping, index|
for key, value in mapping
options.merge!({ format("LaunchSpecification.BlockDeviceMapping.%d.#{key}", index) => value })
end
end
end
if security_groups = options.delete('LaunchSpecification.SecurityGroup')
options.merge!(Fog::AWS.indexed_param('LaunchSpecification.SecurityGroup', [*security_groups]))
end
if options['LaunchSpecification.UserData']
options['LaunchSpecification.UserData'] = Base64.encode64(options['LaunchSpecification.UserData'])
end
request({
'Action' => 'RequestSpotInstances',
'LaunchSpecification.ImageId' => image_id,
'LaunchSpecification.InstanceType' => instance_type,
'SpotPrice' => spot_price,
:parser => Fog::Parsers::Compute::AWS::SpotInstanceRequests.new
}.merge!(options))
end
end
end
end
end

View file

@ -0,0 +1,48 @@
Shindo.tests('Fog::Compute[:aws] | spot datafeed subscription requests', ['aws']) do
@spot_datafeed_subscription_format = {
'spotDatafeedSubscription' => {
'bucket' => String,
'ownerId' => String,
'prefix' => String,
'state' => String
},
'requestId' => String
}
@directory = Fog::Storage[:aws].directories.create(:key => 'fogspotdatafeedsubscriptiontests')
tests('success') do
tests("#create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/')").formats(@spot_datafeed_subscription_format) do
Fog::Compute[:aws].create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/').body
end
tests("duplicate #create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/')").succeeds do
Fog::Compute[:aws].create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/')
end
tests("#describe_spot_datafeed_subscription").formats(@spot_datafeed_subscription_format) do
Fog::Compute[:aws].describe_spot_datafeed_subscription.body
end
tests("#delete_spot_datafeed_subscription").formats(AWS::Compute::Formats::BASIC) do
Fog::Compute[:aws].delete_spot_datafeed_subscription.body
end
tests("duplicate #delete_spot_datafeed_subscription").succeeds do
Fog::Compute[:aws].delete_spot_datafeed_subscription
end
end
tests('failure') do
tests("#describe_spot_datafeed_subscription").raises(Fog::Compute::AWS::NotFound) do
Fog::Compute[:aws].describe_spot_datafeed_subscription
end
end
@directory.destroy
end

View file

@ -0,0 +1,51 @@
Shindo.tests('Fog::Compute[:aws] | spot instance requests', ['aws']) do
@spot_instance_requests_format = {
'spotInstanceRequestSet' => [{
'createTime' => Time,
'instanceId' => Fog::Nullable::String,
'launchedAvailabilityZone' => Fog::Nullable::String,
'launchSpecification' => {
'blockDeviceMapping' => [],
'groupSet' => [String],
'keyName' => Fog::Nullable::String,
'imageId' => String,
'instanceType' => String,
'monitoring' => Fog::Boolean
},
'productDescription' => String,
'spotInstanceRequestId' => String,
'spotPrice' => Float,
'state' => String,
'type' => String
}],
'requestId' => String
}
@cancel_spot_instance_request_format = {
'spotInstanceRequestSet' => [{
'spotInstanceRequestId' => String,
'state' => String
}],
'requestId' => String
}
tests('success') do
tests("#request_spot_instances('ami-3202f25b', 't1.micro', '0.001')").formats(@spot_instance_requests_format) do
data = Fog::Compute[:aws].request_spot_instances('ami-3202f25b', 't1.micro', '0.001').body
@spot_instance_request_id = data['spotInstanceRequestSet'].first['spotInstanceRequestId']
data
end
tests("#describe_spot_instance_requests").formats(@spot_instance_requests_format) do
Fog::Compute[:aws].describe_spot_instance_requests.body
end
tests("#cancel_spot_instance_requests('#{@spot_instance_request_id}')").formats(@cancel_spot_instance_request_format) do
Fog::Compute[:aws].cancel_spot_instance_requests(@spot_instance_request_id).body
end
end
end

View file

@ -0,0 +1,22 @@
Shindo.tests('Fog::Compute[:aws] | spot price history requests', ['aws']) do
@spot_price_history_format = {
'spotPriceHistorySet' => [{
'availabilityZone' => String,
'instanceType' => String,
'spotPrice' => Float,
'productDescription' => String,
'timestamp' => Time
}],
'requestId' => String
}
tests('success') do
tests("#describe_spot_price_history").formats(@spot_price_history_format) do
Fog::Compute[:aws].describe_spot_price_history.body
end
end
end