Have spot requests launch instances.

This commit is contained in:
Steve Pulec 2016-11-07 23:08:30 -05:00
parent 24035877f6
commit 5c3d9b4ae1
5 changed files with 112 additions and 75 deletions

View File

@ -2517,6 +2517,8 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
default_group = self.ec2_backend.get_security_group_from_name("default") default_group = self.ec2_backend.get_security_group_from_name("default")
ls.groups.append(default_group) ls.groups.append(default_group)
self.instance = self.launch_instance()
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
if filter_name == 'state': if filter_name == 'state':
return self.state return self.state
@ -2529,6 +2531,18 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
return filter_value return filter_value
def launch_instance(self):
reservation = self.ec2_backend.add_instances(
image_id=self.launch_specification.image_id, count=1, user_data=self.user_data,
instance_type=self.launch_specification.instance_type,
subnet_id=self.launch_specification.subnet_id,
key_name=self.launch_specification.key_name,
security_group_names=[],
security_group_ids=self.launch_specification.groups,
)
instance = reservation.instances[0]
return instance
@six.add_metaclass(Model) @six.add_metaclass(Model)
class SpotRequestBackend(object): class SpotRequestBackend(object):

View File

@ -98,9 +98,9 @@ DESCRIBE_SPOT_FLEET_INSTANCES_TEMPLATE = """<DescribeSpotFleetInstancesResponse
<activeInstanceSet> <activeInstanceSet>
{% for spot_request in spot_requests %} {% for spot_request in spot_requests %}
<item> <item>
<instanceId>{{ spot_request.instance_id }}</instanceId> <instanceId>{{ spot_request.instance.id }}</instanceId>
<spotInstanceRequestId>{{ spot_request.id }}</spotInstanceRequestId> <spotInstanceRequestId>{{ spot_request.id }}</spotInstanceRequestId>
<instanceType>{{ spot_request.instance_type }}</instanceType> <instanceType>{{ spot_request.instance.instance_type }}</instanceType>
</item> </item>
{% endfor %} {% endfor %}
</activeInstanceSet> </activeInstanceSet>

View File

@ -1881,6 +1881,12 @@ def test_stack_kms():
@mock_cloudformation() @mock_cloudformation()
@mock_ec2() @mock_ec2()
def test_stack_spot_fleet(): def test_stack_spot_fleet():
conn = boto3.client('ec2', 'us-east-1')
vpc = conn.create_vpc(CidrBlock="10.0.0.0/8")['Vpc']
subnet = conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.0.0.0/16', AvailabilityZone='us-east-1a')['Subnet']
subnet_id = subnet['SubnetId']
spot_fleet_template = { spot_fleet_template = {
'Resources': { 'Resources': {
"SpotFleet": { "SpotFleet": {
@ -1896,7 +1902,7 @@ def test_stack_spot_fleet():
"EbsOptimized": "false", "EbsOptimized": "false",
"InstanceType": 't2.small', "InstanceType": 't2.small',
"ImageId": "ami-1234", "ImageId": "ami-1234",
"SubnetId": "subnet-123", "SubnetId": subnet_id,
"WeightedCapacity": "2", "WeightedCapacity": "2",
"SpotPrice": "0.13", "SpotPrice": "0.13",
}, },
@ -1906,7 +1912,7 @@ def test_stack_spot_fleet():
"ImageId": "ami-1234", "ImageId": "ami-1234",
"Monitoring": { "Enabled": "true" }, "Monitoring": { "Enabled": "true" },
"SecurityGroups": [{"GroupId": "sg-123"}], "SecurityGroups": [{"GroupId": "sg-123"}],
"SubnetId": "subnet-123", "SubnetId": subnet_id,
"IamInstanceProfile": {"Arn": "arn:aws:iam::123456789012:role/fleet"}, "IamInstanceProfile": {"Arn": "arn:aws:iam::123456789012:role/fleet"},
"WeightedCapacity": "4", "WeightedCapacity": "4",
"SpotPrice": "10.00", "SpotPrice": "10.00",
@ -1929,7 +1935,6 @@ def test_stack_spot_fleet():
stack_resources['StackResourceSummaries'].should.have.length_of(1) stack_resources['StackResourceSummaries'].should.have.length_of(1)
spot_fleet_id = stack_resources['StackResourceSummaries'][0]['PhysicalResourceId'] spot_fleet_id = stack_resources['StackResourceSummaries'][0]['PhysicalResourceId']
conn = boto3.client('ec2', 'us-east-1')
spot_fleet_requests = conn.describe_spot_fleet_requests(SpotFleetRequestIds=[spot_fleet_id])['SpotFleetRequestConfigs'] spot_fleet_requests = conn.describe_spot_fleet_requests(SpotFleetRequestIds=[spot_fleet_id])['SpotFleetRequestConfigs']
len(spot_fleet_requests).should.equal(1) len(spot_fleet_requests).should.equal(1)
spot_fleet_request = spot_fleet_requests[0] spot_fleet_request = spot_fleet_requests[0]
@ -1948,6 +1953,6 @@ def test_stack_spot_fleet():
launch_spec['EbsOptimized'].should.equal(False) launch_spec['EbsOptimized'].should.equal(False)
launch_spec['ImageId'].should.equal("ami-1234") launch_spec['ImageId'].should.equal("ami-1234")
launch_spec['InstanceType'].should.equal("t2.small") launch_spec['InstanceType'].should.equal("t2.small")
launch_spec['SubnetId'].should.equal("subnet-123") launch_spec['SubnetId'].should.equal(subnet_id)
launch_spec['SpotPrice'].should.equal("0.13") launch_spec['SpotPrice'].should.equal("0.13")
launch_spec['WeightedCapacity'].should.equal(2.0) launch_spec['WeightedCapacity'].should.equal(2.0)

View File

@ -5,7 +5,15 @@ import sure # noqa
from moto import mock_ec2 from moto import mock_ec2
SPOT_REQUEST_CONFIG = { def get_subnet_id(conn):
vpc = conn.create_vpc(CidrBlock="10.0.0.0/8")['Vpc']
subnet = conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.0.0.0/16', AvailabilityZone='us-east-1a')['Subnet']
subnet_id = subnet['SubnetId']
return subnet_id
def spot_config(subnet_id, allocation_strategy="lowestPrice"):
return {
'ClientToken': 'string', 'ClientToken': 'string',
'SpotPrice': '0.12', 'SpotPrice': '0.12',
'TargetCapacity': 6, 'TargetCapacity': 6,
@ -38,7 +46,7 @@ SPOT_REQUEST_CONFIG = {
'Monitoring': { 'Monitoring': {
'Enabled': True 'Enabled': True
}, },
'SubnetId': 'subnet-1234', 'SubnetId': subnet_id,
'IamInstanceProfile': { 'IamInstanceProfile': {
'Arn': 'arn:aws:iam::123456789012:role/fleet' 'Arn': 'arn:aws:iam::123456789012:role/fleet'
}, },
@ -58,7 +66,7 @@ SPOT_REQUEST_CONFIG = {
'Monitoring': { 'Monitoring': {
'Enabled': True 'Enabled': True
}, },
'SubnetId': 'subnet-1234', 'SubnetId': subnet_id,
'IamInstanceProfile': { 'IamInstanceProfile': {
'Arn': 'arn:aws:iam::123456789012:role/fleet' 'Arn': 'arn:aws:iam::123456789012:role/fleet'
}, },
@ -66,7 +74,7 @@ SPOT_REQUEST_CONFIG = {
'WeightedCapacity': 4.0, 'WeightedCapacity': 4.0,
'SpotPrice': '10.00', 'SpotPrice': '10.00',
}], }],
'AllocationStrategy': 'lowestPrice', 'AllocationStrategy': allocation_strategy,
'FulfilledCapacity': 6, 'FulfilledCapacity': 6,
} }
@ -74,9 +82,10 @@ SPOT_REQUEST_CONFIG = {
@mock_ec2 @mock_ec2
def test_create_spot_fleet_with_lowest_price(): def test_create_spot_fleet_with_lowest_price():
conn = boto3.client("ec2", region_name='us-west-2') conn = boto3.client("ec2", region_name='us-west-2')
subnet_id = get_subnet_id(conn)
spot_fleet_res = conn.request_spot_fleet( spot_fleet_res = conn.request_spot_fleet(
SpotFleetRequestConfig=SPOT_REQUEST_CONFIG SpotFleetRequestConfig=spot_config(subnet_id)
) )
spot_fleet_id = spot_fleet_res['SpotFleetRequestId'] spot_fleet_id = spot_fleet_res['SpotFleetRequestId']
@ -103,7 +112,7 @@ def test_create_spot_fleet_with_lowest_price():
launch_spec['KeyName'].should.equal("my-key") launch_spec['KeyName'].should.equal("my-key")
launch_spec['Monitoring'].should.equal({"Enabled": True}) launch_spec['Monitoring'].should.equal({"Enabled": True})
launch_spec['SpotPrice'].should.equal("0.13") launch_spec['SpotPrice'].should.equal("0.13")
launch_spec['SubnetId'].should.equal("subnet-1234") launch_spec['SubnetId'].should.equal(subnet_id)
launch_spec['UserData'].should.equal("some user data") launch_spec['UserData'].should.equal("some user data")
launch_spec['WeightedCapacity'].should.equal(2.0) launch_spec['WeightedCapacity'].should.equal(2.0)
@ -115,8 +124,8 @@ def test_create_spot_fleet_with_lowest_price():
@mock_ec2 @mock_ec2
def test_create_diversified_spot_fleet(): def test_create_diversified_spot_fleet():
conn = boto3.client("ec2", region_name='us-west-2') conn = boto3.client("ec2", region_name='us-west-2')
diversified_config = SPOT_REQUEST_CONFIG.copy() subnet_id = get_subnet_id(conn)
diversified_config['AllocationStrategy'] = 'diversified' diversified_config = spot_config(subnet_id, allocation_strategy='diversified')
spot_fleet_res = conn.request_spot_fleet( spot_fleet_res = conn.request_spot_fleet(
SpotFleetRequestConfig=diversified_config SpotFleetRequestConfig=diversified_config
@ -126,14 +135,17 @@ def test_create_diversified_spot_fleet():
instance_res = conn.describe_spot_fleet_instances(SpotFleetRequestId=spot_fleet_id) instance_res = conn.describe_spot_fleet_instances(SpotFleetRequestId=spot_fleet_id)
instances = instance_res['ActiveInstances'] instances = instance_res['ActiveInstances']
len(instances).should.equal(2) len(instances).should.equal(2)
instances[0]['InstanceType'].should.equal("t2.small")
instances[0]['InstanceId'].should.contain("i-")
@mock_ec2 @mock_ec2
def test_cancel_spot_fleet_request(): def test_cancel_spot_fleet_request():
conn = boto3.client("ec2", region_name='us-west-2') conn = boto3.client("ec2", region_name='us-west-2')
subnet_id = get_subnet_id(conn)
spot_fleet_res = conn.request_spot_fleet( spot_fleet_res = conn.request_spot_fleet(
SpotFleetRequestConfig=SPOT_REQUEST_CONFIG, SpotFleetRequestConfig=spot_config(subnet_id),
) )
spot_fleet_id = spot_fleet_res['SpotFleetRequestId'] spot_fleet_id = spot_fleet_res['SpotFleetRequestId']

View File

@ -3,6 +3,7 @@ from nose.tools import assert_raises
import datetime import datetime
import boto import boto
import boto3
import sure # noqa import sure # noqa
from boto.exception import JSONResponseError from boto.exception import JSONResponseError
@ -13,6 +14,11 @@ from moto.core.utils import iso_8601_datetime_with_milliseconds
@mock_ec2 @mock_ec2
def test_request_spot_instances(): def test_request_spot_instances():
conn = boto3.client('ec2', 'us-east-1')
vpc = conn.create_vpc(CidrBlock="10.0.0.0/8")['Vpc']
subnet = conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.0.0.0/16', AvailabilityZone='us-east-1a')['Subnet']
subnet_id = subnet['SubnetId']
conn = boto.connect_ec2() conn = boto.connect_ec2()
conn.create_security_group('group1', 'description') conn.create_security_group('group1', 'description')
@ -29,7 +35,7 @@ def test_request_spot_instances():
security_groups=['group1', 'group2'], user_data=b"some test data", security_groups=['group1', 'group2'], user_data=b"some test data",
instance_type='m1.small', placement='us-east-1c', instance_type='m1.small', placement='us-east-1c',
kernel_id="test-kernel", ramdisk_id="test-ramdisk", kernel_id="test-kernel", ramdisk_id="test-ramdisk",
monitoring_enabled=True, subnet_id="subnet123", dry_run=True monitoring_enabled=True, subnet_id=subnet_id, dry_run=True
) )
ex.exception.reason.should.equal('DryRunOperation') ex.exception.reason.should.equal('DryRunOperation')
ex.exception.status.should.equal(400) ex.exception.status.should.equal(400)
@ -42,7 +48,7 @@ def test_request_spot_instances():
security_groups=['group1', 'group2'], user_data=b"some test data", security_groups=['group1', 'group2'], user_data=b"some test data",
instance_type='m1.small', placement='us-east-1c', instance_type='m1.small', placement='us-east-1c',
kernel_id="test-kernel", ramdisk_id="test-ramdisk", kernel_id="test-kernel", ramdisk_id="test-ramdisk",
monitoring_enabled=True, subnet_id="subnet123", monitoring_enabled=True, subnet_id=subnet_id,
) )
requests = conn.get_all_spot_instance_requests() requests = conn.get_all_spot_instance_requests()
@ -64,7 +70,7 @@ def test_request_spot_instances():
request.launch_specification.placement.should.equal('us-east-1c') request.launch_specification.placement.should.equal('us-east-1c')
request.launch_specification.kernel.should.equal("test-kernel") request.launch_specification.kernel.should.equal("test-kernel")
request.launch_specification.ramdisk.should.equal("test-ramdisk") request.launch_specification.ramdisk.should.equal("test-ramdisk")
request.launch_specification.subnet_id.should.equal("subnet123") request.launch_specification.subnet_id.should.equal(subnet_id)
@mock_ec2 @mock_ec2