From a9f215c16e23c4de5fd571fae65d373a210f95e1 Mon Sep 17 00:00:00 2001 From: Eugene Howe Date: Thu, 23 Feb 2017 10:23:37 -0500 Subject: [PATCH] mock spot requests --- lib/fog/aws/compute.rb | 3 +- lib/fog/aws/models/compute/spot_request.rb | 5 +- .../compute/cancel_spot_instance_requests.rb | 17 ++++++ .../requests/compute/describe_instances.rb | 2 +- .../describe_spot_instance_requests.rb | 33 ++++++++++++ .../compute/request_spot_instances.rb | 53 +++++++++++-------- lib/fog/aws/requests/compute/run_instances.rb | 51 +++++++++--------- tests/requests/compute/spot_instance_tests.rb | 4 +- 8 files changed, 115 insertions(+), 53 deletions(-) diff --git a/lib/fog/aws/compute.rb b/lib/fog/aws/compute.rb index 222a98066..85830e1f7 100644 --- a/lib/fog/aws/compute.rb +++ b/lib/fog/aws/compute.rb @@ -288,7 +288,8 @@ module Fog "values" => ["5"], "attributeName" => "vpc-max-elastic-ips" } - ] + ], + :spot_requests => {}, } end end diff --git a/lib/fog/aws/models/compute/spot_request.rb b/lib/fog/aws/models/compute/spot_request.rb index cd7879d35..c95df6caf 100644 --- a/lib/fog/aws/models/compute/spot_request.rb +++ b/lib/fog/aws/models/compute/spot_request.rb @@ -21,6 +21,7 @@ module Fog attribute :ebs_optimized, :aliases => 'LaunchSpecification.EbsOptimized' attribute :groups, :aliases => 'LaunchSpecification.SecurityGroup' + attribute :security_group_ids, :aliases => 'LaunchSpecification.SecurityGroupId' attribute :key_name, :aliases => 'LaunchSpecification.KeyName' attribute :availability_zone, :aliases => 'LaunchSpecification.Placement.AvailabilityZone' attribute :flavor_id, :aliases => 'LaunchSpecification.InstanceType' @@ -37,7 +38,7 @@ module Fog attr_writer :iam_instance_profile_name, :iam_instance_profile_arn def initialize(attributes={}) - self.groups ||= ["default"] + self.groups ||= self.security_group_ids || ["default"] self.flavor_id ||= 't1.micro' self.image_id ||= begin self.username ||= 'ubuntu' @@ -93,7 +94,7 @@ module Fog 'LaunchSpecification.KeyName' => key_name, 'LaunchSpecification.Monitoring.Enabled' => monitoring, 'LaunchSpecification.Placement.AvailabilityZone' => availability_zone, - 'LaunchSpecification.SecurityGroupId' => groups, + 'LaunchSpecification.SecurityGroupId' => security_group_ids || groups, 'LaunchSpecification.EbsOptimized' => ebs_optimized, 'LaunchSpecification.UserData' => user_data, 'LaunchSpecification.SubnetId' => subnet_id, diff --git a/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb b/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb index 01f1e09d0..aa40f3d1c 100644 --- a/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb +++ b/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb @@ -27,6 +27,23 @@ module Fog }.merge!(params)) end end + + class Mock + def cancel_spot_instance_requests(spot_instance_request_id) + response = Excon::Response.new + spot_request = self.data[:spot_requests][spot_instance_request_id] + + unless spot_request + raise Fog::Compute::AWS::NotFound.new("The spot instance request ID '#{spot_instance_request_id}' does not exist") + end + + spot_request['fault']['code'] = 'request-cancelled' + spot_request['state'] = 'cancelled' + + response.body = {'spotInstanceRequestSet' => [{'spotInstanceRequestId' => spot_instance_request_id, 'state' => 'cancelled'}], 'requestId' => Fog::AWS::Mock.request_id} + response + end + end end end end diff --git a/lib/fog/aws/requests/compute/describe_instances.rb b/lib/fog/aws/requests/compute/describe_instances.rb index 726a2f811..e6867f2d1 100644 --- a/lib/fog/aws/requests/compute/describe_instances.rb +++ b/lib/fog/aws/requests/compute/describe_instances.rb @@ -249,7 +249,7 @@ module Fog 'ownerId' => instance['ownerId'], 'reservationId' => instance['reservationId'] } - reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'ebsOptimized', 'hypervisor', 'iamInstanceProfile', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'networkInterfaces', 'ownerId', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceName', 'rootDeviceType', 'stateReason', 'subnetId', 'virtualizationType'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']]) + reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'ebsOptimized', 'hypervisor', 'iamInstanceProfile', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'networkInterfaces', 'ownerId', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceName', 'rootDeviceType', 'spotInstanceRequestId', 'stateReason', 'subnetId', 'virtualizationType'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']]) end end diff --git a/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb b/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb index a65b5147d..b24e4e336 100644 --- a/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb +++ b/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb @@ -41,6 +41,39 @@ module Fog }.merge!(params)) end end + + class Mock + def describe_spot_instance_requests(filters = {}) + response = Excon::Response.new + spot_requests = self.data[:spot_requests].values + + if id = Array(filters['spot-instance-request-id']).first + spot_requests = spot_requests.select { |r| r['spotInstanceRequestId'] == id } + end + + spot_requests.select { |r| r['instanceId'].nil? }.each do |request| + run_instance_options = { + 'BlockDeviceMapping' => request['launchSpecification']['blockDeviceMapping'], + 'EbsOptimized' => request['launchSpecification']['ebsOptimized'], + 'KeyName' => request['launchSpecification']['keyName'], + 'SecurityGroupId' => request['launchSpecification']['groupSet'].first, + 'SpotInstanceRequestId' => request['spotInstanceRequestId'], + 'SubnetId' => request['launchSpecification']['subnetId'] + } + instances = run_instances(request['launchSpecification']['imageId'], 1,1, run_instance_options).body['instancesSet'] + + request['instanceId'] = instances.first['instanceId'] + request['state'] = 'active' + request['fault'] = {'code' => 'fulfilled', 'message' => 'Your Spot request is fulfilled.'} + request['launchedAvailabilityZone'] = instances.first['placement']['availabilityZone'] + + self.data[:spot_requests][request['spotInstanceRequestId']] = request + end + + response.body = {'spotInstanceRequestSet' => spot_requests, 'requestId' => Fog::AWS::Mock.request_id} + response + end + end end end end diff --git a/lib/fog/aws/requests/compute/request_spot_instances.rb b/lib/fog/aws/requests/compute/request_spot_instances.rb index 4f0698e42..56a701648 100644 --- a/lib/fog/aws/requests/compute/request_spot_instances.rb +++ b/lib/fog/aws/requests/compute/request_spot_instances.rb @@ -95,6 +95,7 @@ module Fog class Mock def request_spot_instances(image_id, instance_type, spot_price, options = {}) response = Excon::Response.new + id = Fog::AWS::Mock.spot_instance_request_id if (image_id && instance_type && spot_price) response.status = 200 @@ -139,32 +140,42 @@ module Fog launch_spec = { 'iamInstanceProfile' => {}, - 'blockDeviceMapping' => [], - 'groupSet' => [Fog::AWS::Mock.security_group_id], + 'blockDeviceMapping' => options['LaunchSpecification.BlockDeviceMapping'] || [], + 'groupSet' => options['LaunchSpecification.SecurityGroupId'] || ['default'], 'imageId' => image_id, 'instanceType' => instance_type, - 'monitoring' => options['MonitoringEnabled'] || false, - 'subnetId' => nil, - 'ebsOptimized' => false, - 'keyName' => options['KeyName'] || nil + 'monitoring' => options['LaunchSpecification.Monitoring.Enabled'] || false, + 'subnetId' => options['LaunchSpecification.SubnetId'] || nil, + 'ebsOptimized' => options['LaunchSpecification.EbsOptimized'] || false, + 'keyName' => options['LaunchSpecification.KeyName'] || nil } + if iam_arn = options['LaunchSpecification.IamInstanceProfile.Arn'] + launch_spec['iamInstanceProfile'].merge!('Arn' => iam_arn) + end + + if iam_name = options['LaunchSpecification.IamInstanceProfile.Name'] + launch_spec['iamInstanceProfile'].merge!('Name' => iam_name) + end + + spot_request = { + 'launchSpecification' => launch_spec, + 'spotInstanceRequestId' => id, + 'spotPrice' => spot_price, + 'type' => options['Type'] || 'one-time', + 'state' => 'open', + 'fault' => { + 'code' => 'pending-evaluation', + 'message' => 'Your Spot request has been submitted for review, and is pending evaluation.' + }, + 'createTime' => Time.now, + 'productDescription' => 'Linux/UNIX' + } + + self.data[:spot_requests][id] = spot_request + response.body = { - 'spotInstanceRequestSet' => [ - { - 'launchSpecification' => launch_spec, - 'spotInstanceRequestId' => Fog::AWS::Mock.spot_instance_request_id, - 'spotPrice' => spot_price, - 'type' => options['Type'] || 'one-time', - 'state' => 'open', - 'fault' => { - 'code' => 'pending-evaluation', - 'message' => 'Your Spot request has been submitted for review, and is pending evaluation.' - }, - 'createTime' => Time.now, - 'productDescription' => 'Linux/UNIX' - } - ], + 'spotInstanceRequestSet' => [spot_request], 'requestId' => Fog::AWS::Mock.request_id } diff --git a/lib/fog/aws/requests/compute/run_instances.rb b/lib/fog/aws/requests/compute/run_instances.rb index 50ded05b5..4e38d80e9 100644 --- a/lib/fog/aws/requests/compute/run_instances.rb +++ b/lib/fog/aws/requests/compute/run_instances.rb @@ -217,31 +217,32 @@ module Fog end instance = { - 'amiLaunchIndex' => i, - 'associatePublicIP' => options['associatePublicIP'] || false, - 'architecture' => 'i386', - 'blockDeviceMapping' => block_device_mapping, - 'networkInterfaces' => network_interfaces, - 'clientToken' => options['clientToken'], - 'dnsName' => nil, - 'ebsOptimized' => options['EbsOptimized'] || false, - 'hypervisor' => 'xen', - 'imageId' => image_id, - 'instanceId' => instance_id, - 'instanceState' => { 'code' => 0, 'name' => 'pending' }, - 'instanceType' => options['InstanceType'] || 'm1.small', - 'kernelId' => options['KernelId'] || Fog::AWS::Mock.kernel_id, - 'keyName' => options['KeyName'], - 'launchTime' => Time.now, - 'monitoring' => { 'state' => options['Monitoring.Enabled'] || false }, - 'placement' => { 'availabilityZone' => availability_zone, 'groupName' => nil, 'tenancy' => options['Placement.Tenancy'] || 'default' }, - 'privateDnsName' => nil, - 'productCodes' => [], - 'reason' => nil, - 'rootDeviceName' => block_device_mapping.first && block_device_mapping.first["deviceName"], - 'rootDeviceType' => 'instance-store', - 'subnetId' => options['SubnetId'], - 'virtualizationType' => 'paravirtual' + 'amiLaunchIndex' => i, + 'associatePublicIP' => options['associatePublicIP'] || false, + 'architecture' => 'i386', + 'blockDeviceMapping' => block_device_mapping, + 'networkInterfaces' => network_interfaces, + 'clientToken' => options['clientToken'], + 'dnsName' => nil, + 'ebsOptimized' => options['EbsOptimized'] || false, + 'hypervisor' => 'xen', + 'imageId' => image_id, + 'instanceId' => instance_id, + 'instanceState' => { 'code' => 0, 'name' => 'pending' }, + 'instanceType' => options['InstanceType'] || 'm1.small', + 'kernelId' => options['KernelId'] || Fog::AWS::Mock.kernel_id, + 'keyName' => options['KeyName'], + 'launchTime' => Time.now, + 'monitoring' => { 'state' => options['Monitoring.Enabled'] || false }, + 'placement' => { 'availabilityZone' => availability_zone, 'groupName' => nil, 'tenancy' => options['Placement.Tenancy'] || 'default' }, + 'privateDnsName' => nil, + 'productCodes' => [], + 'reason' => nil, + 'rootDeviceName' => block_device_mapping.first && block_device_mapping.first["deviceName"], + 'rootDeviceType' => 'instance-store', + 'spotInstanceRequestId' => options['SpotInstanceRequestId'], + 'subnetId' => options['SubnetId'], + 'virtualizationType' => 'paravirtual' } instances_set << instance self.data[:instances][instance_id] = instance.merge({ diff --git a/tests/requests/compute/spot_instance_tests.rb b/tests/requests/compute/spot_instance_tests.rb index be3669241..6052f4eed 100644 --- a/tests/requests/compute/spot_instance_tests.rb +++ b/tests/requests/compute/spot_instance_tests.rb @@ -42,10 +42,8 @@ Shindo.tests('Fog::Compute[:aws] | spot instance requests', ['aws']) do data end - pending if Fog.mocking? - tests("#describe_spot_instance_requests").formats(@spot_instance_requests_format) do - Fog::Compute[:aws].describe_spot_instance_requests('spot-instance-request-id' => [@spot_instance_request_id]).body + data = Fog::Compute[:aws].describe_spot_instance_requests('spot-instance-request-id' => [@spot_instance_request_id]).body end tests("#cancel_spot_instance_requests('#{@spot_instance_request_id}')").formats(@cancel_spot_instance_request_format) do