diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 3c4da13b4..02638e3b9 100755 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -2517,6 +2517,8 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource): default_group = self.ec2_backend.get_security_group_from_name("default") ls.groups.append(default_group) + self.instance = self.launch_instance() + def get_filter_value(self, filter_name): if filter_name == 'state': return self.state @@ -2529,6 +2531,18 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource): 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) class SpotRequestBackend(object): diff --git a/moto/ec2/responses/spot_fleets.py b/moto/ec2/responses/spot_fleets.py index f49b60e68..3004cc0bb 100644 --- a/moto/ec2/responses/spot_fleets.py +++ b/moto/ec2/responses/spot_fleets.py @@ -98,9 +98,9 @@ DESCRIBE_SPOT_FLEET_INSTANCES_TEMPLATE = """ {% for spot_request in spot_requests %} - {{ spot_request.instance_id }} + {{ spot_request.instance.id }} {{ spot_request.id }} - {{ spot_request.instance_type }} + {{ spot_request.instance.instance_type }} {% endfor %} diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index 59a179618..684b7e420 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -1881,6 +1881,12 @@ def test_stack_kms(): @mock_cloudformation() @mock_ec2() 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 = { 'Resources': { "SpotFleet": { @@ -1896,7 +1902,7 @@ def test_stack_spot_fleet(): "EbsOptimized": "false", "InstanceType": 't2.small', "ImageId": "ami-1234", - "SubnetId": "subnet-123", + "SubnetId": subnet_id, "WeightedCapacity": "2", "SpotPrice": "0.13", }, @@ -1906,7 +1912,7 @@ def test_stack_spot_fleet(): "ImageId": "ami-1234", "Monitoring": { "Enabled": "true" }, "SecurityGroups": [{"GroupId": "sg-123"}], - "SubnetId": "subnet-123", + "SubnetId": subnet_id, "IamInstanceProfile": {"Arn": "arn:aws:iam::123456789012:role/fleet"}, "WeightedCapacity": "4", "SpotPrice": "10.00", @@ -1929,7 +1935,6 @@ def test_stack_spot_fleet(): stack_resources['StackResourceSummaries'].should.have.length_of(1) 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'] len(spot_fleet_requests).should.equal(1) spot_fleet_request = spot_fleet_requests[0] @@ -1948,6 +1953,6 @@ def test_stack_spot_fleet(): launch_spec['EbsOptimized'].should.equal(False) launch_spec['ImageId'].should.equal("ami-1234") 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['WeightedCapacity'].should.equal(2.0) diff --git a/tests/test_ec2/test_spot_fleet.py b/tests/test_ec2/test_spot_fleet.py index 9a52ec80b..f33784fc3 100644 --- a/tests/test_ec2/test_spot_fleet.py +++ b/tests/test_ec2/test_spot_fleet.py @@ -5,78 +5,87 @@ import sure # noqa from moto import mock_ec2 -SPOT_REQUEST_CONFIG = { - 'ClientToken': 'string', - 'SpotPrice': '0.12', - 'TargetCapacity': 6, - 'IamFleetRole': 'arn:aws:iam::123456789012:role/fleet', - 'LaunchSpecifications': [{ - 'ImageId': 'ami-123', - 'KeyName': 'my-key', - 'SecurityGroups': [ - { - 'GroupId': 'sg-123' - }, - ], - 'UserData': 'some user data', - 'InstanceType': 't2.small', - 'BlockDeviceMappings': [ - { - 'VirtualName': 'string', - 'DeviceName': 'string', - 'Ebs': { - 'SnapshotId': 'string', - 'VolumeSize': 123, - 'DeleteOnTermination': True|False, - 'VolumeType': 'standard', - 'Iops': 123, - 'Encrypted': True|False +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', + 'SpotPrice': '0.12', + 'TargetCapacity': 6, + 'IamFleetRole': 'arn:aws:iam::123456789012:role/fleet', + 'LaunchSpecifications': [{ + 'ImageId': 'ami-123', + 'KeyName': 'my-key', + 'SecurityGroups': [ + { + 'GroupId': 'sg-123' }, - 'NoDevice': 'string' + ], + 'UserData': 'some user data', + 'InstanceType': 't2.small', + 'BlockDeviceMappings': [ + { + 'VirtualName': 'string', + 'DeviceName': 'string', + 'Ebs': { + 'SnapshotId': 'string', + 'VolumeSize': 123, + 'DeleteOnTermination': True|False, + 'VolumeType': 'standard', + 'Iops': 123, + 'Encrypted': True|False + }, + 'NoDevice': 'string' + }, + ], + 'Monitoring': { + 'Enabled': True }, - ], - 'Monitoring': { - 'Enabled': True - }, - 'SubnetId': 'subnet-1234', - 'IamInstanceProfile': { - 'Arn': 'arn:aws:iam::123456789012:role/fleet' - }, - 'EbsOptimized': False, - 'WeightedCapacity': 2.0, - 'SpotPrice': '0.13' - }, { - 'ImageId': 'ami-123', - 'KeyName': 'my-key', - 'SecurityGroups': [ - { - 'GroupId': 'sg-123' + 'SubnetId': subnet_id, + 'IamInstanceProfile': { + 'Arn': 'arn:aws:iam::123456789012:role/fleet' }, - ], - 'UserData': 'some user data', - 'InstanceType': 't2.large', - 'Monitoring': { - 'Enabled': True - }, - 'SubnetId': 'subnet-1234', - 'IamInstanceProfile': { - 'Arn': 'arn:aws:iam::123456789012:role/fleet' - }, - 'EbsOptimized': False, - 'WeightedCapacity': 4.0, - 'SpotPrice': '10.00', - }], - 'AllocationStrategy': 'lowestPrice', - 'FulfilledCapacity': 6, -} + 'EbsOptimized': False, + 'WeightedCapacity': 2.0, + 'SpotPrice': '0.13' + }, { + 'ImageId': 'ami-123', + 'KeyName': 'my-key', + 'SecurityGroups': [ + { + 'GroupId': 'sg-123' + }, + ], + 'UserData': 'some user data', + 'InstanceType': 't2.large', + 'Monitoring': { + 'Enabled': True + }, + 'SubnetId': subnet_id, + 'IamInstanceProfile': { + 'Arn': 'arn:aws:iam::123456789012:role/fleet' + }, + 'EbsOptimized': False, + 'WeightedCapacity': 4.0, + 'SpotPrice': '10.00', + }], + 'AllocationStrategy': allocation_strategy, + 'FulfilledCapacity': 6, + } @mock_ec2 def test_create_spot_fleet_with_lowest_price(): conn = boto3.client("ec2", region_name='us-west-2') + subnet_id = get_subnet_id(conn) spot_fleet_res = conn.request_spot_fleet( - SpotFleetRequestConfig=SPOT_REQUEST_CONFIG + SpotFleetRequestConfig=spot_config(subnet_id) ) 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['Monitoring'].should.equal({"Enabled": True}) 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['WeightedCapacity'].should.equal(2.0) @@ -115,8 +124,8 @@ def test_create_spot_fleet_with_lowest_price(): @mock_ec2 def test_create_diversified_spot_fleet(): conn = boto3.client("ec2", region_name='us-west-2') - diversified_config = SPOT_REQUEST_CONFIG.copy() - diversified_config['AllocationStrategy'] = 'diversified' + subnet_id = get_subnet_id(conn) + diversified_config = spot_config(subnet_id, allocation_strategy='diversified') spot_fleet_res = conn.request_spot_fleet( SpotFleetRequestConfig=diversified_config @@ -126,14 +135,17 @@ def test_create_diversified_spot_fleet(): instance_res = conn.describe_spot_fleet_instances(SpotFleetRequestId=spot_fleet_id) instances = instance_res['ActiveInstances'] len(instances).should.equal(2) + instances[0]['InstanceType'].should.equal("t2.small") + instances[0]['InstanceId'].should.contain("i-") @mock_ec2 def test_cancel_spot_fleet_request(): conn = boto3.client("ec2", region_name='us-west-2') + subnet_id = get_subnet_id(conn) spot_fleet_res = conn.request_spot_fleet( - SpotFleetRequestConfig=SPOT_REQUEST_CONFIG, + SpotFleetRequestConfig=spot_config(subnet_id), ) spot_fleet_id = spot_fleet_res['SpotFleetRequestId'] diff --git a/tests/test_ec2/test_spot_instances.py b/tests/test_ec2/test_spot_instances.py index 2f4f50406..790ffeb65 100644 --- a/tests/test_ec2/test_spot_instances.py +++ b/tests/test_ec2/test_spot_instances.py @@ -3,6 +3,7 @@ from nose.tools import assert_raises import datetime import boto +import boto3 import sure # noqa from boto.exception import JSONResponseError @@ -13,6 +14,11 @@ from moto.core.utils import iso_8601_datetime_with_milliseconds @mock_ec2 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.create_security_group('group1', 'description') @@ -29,7 +35,7 @@ def test_request_spot_instances(): security_groups=['group1', 'group2'], user_data=b"some test data", instance_type='m1.small', placement='us-east-1c', 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.status.should.equal(400) @@ -42,7 +48,7 @@ def test_request_spot_instances(): security_groups=['group1', 'group2'], user_data=b"some test data", instance_type='m1.small', placement='us-east-1c', 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() @@ -64,7 +70,7 @@ def test_request_spot_instances(): request.launch_specification.placement.should.equal('us-east-1c') request.launch_specification.kernel.should.equal("test-kernel") 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