diff --git a/moto/ec2/models.py b/moto/ec2/models.py
index c2fa8480c..d8345da81 100644
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -526,6 +526,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
super(Instance, self).__init__()
self.ec2_backend = ec2_backend
self.id = random_instance_id()
+ self.lifecycle = kwargs.get("lifecycle", "")
self.image_id = image_id
self._state = InstanceState("running", 16)
self._reason = ""
@@ -1001,6 +1002,8 @@ class InstanceBackend(object):
)
else:
new_instance.setup_defaults()
+ if kwargs.get("instance_market_options"):
+ new_instance.lifecycle = "spot"
# Tag all created volumes.
for _, device in new_instance.get_block_device_mapping:
volumes = self.describe_volumes(volume_ids=[device.volume_id])
@@ -5172,6 +5175,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
security_group_ids=self.launch_specification.groups,
spot_fleet_id=self.spot_fleet_id,
tags=self.tags,
+ lifecycle="spot",
)
instance = reservation.instances[0]
return instance
diff --git a/moto/ec2/responses/instances.py b/moto/ec2/responses/instances.py
index b92b2ea1b..82098a04a 100644
--- a/moto/ec2/responses/instances.py
+++ b/moto/ec2/responses/instances.py
@@ -62,6 +62,10 @@ class InstanceResponse(BaseResponse):
"associate_public_ip": self._get_param("AssociatePublicIpAddress"),
"tags": self._parse_tag_specification("TagSpecification"),
"ebs_optimized": self._get_param("EbsOptimized") or False,
+ "instance_market_options": self._get_param(
+ "InstanceMarketOptions.MarketType"
+ )
+ or {},
"instance_initiated_shutdown_behavior": self._get_param(
"InstanceInitiatedShutdownBehavior"
),
@@ -382,6 +386,7 @@ EC2_RUN_INSTANCES = (
{{ instance.ami_launch_index }}
{{ instance.instance_type }}
{{ instance.launch_time }}
+ {{ instance.lifecycle }}
{{ instance.placement}}
@@ -533,6 +538,7 @@ EC2_DESCRIBE_INSTANCES = (
{{ instance.instance_type }}
{{ instance.launch_time }}
+ {{ instance.lifecycle }}
{{ instance.placement }}
diff --git a/moto/packages/boto/ec2/instance.py b/moto/packages/boto/ec2/instance.py
index 3ba81ee95..38da9b9f6 100644
--- a/moto/packages/boto/ec2/instance.py
+++ b/moto/packages/boto/ec2/instance.py
@@ -177,6 +177,7 @@ class Instance(TaggedEC2Object):
self.monitoring_state = None
self.spot_instance_request_id = None
self.subnet_id = None
+ self.lifecycle = None
self.vpc_id = None
self.private_ip_address = None
self.ip_address = None
diff --git a/moto/packages/boto/ec2/launchspecification.py b/moto/packages/boto/ec2/launchspecification.py
index df6c99fc5..a667063bb 100644
--- a/moto/packages/boto/ec2/launchspecification.py
+++ b/moto/packages/boto/ec2/launchspecification.py
@@ -39,6 +39,7 @@ class LaunchSpecification(EC2Object):
self.ramdisk = None
self.monitored = False
self.subnet_id = None
+ self.lifecycle = None
self._in_monitoring_element = False
self.block_device_mapping = None
self.instance_profile = None
diff --git a/tests/test_ec2/test_spot_instances.py b/tests/test_ec2/test_spot_instances.py
index 0c226186b..5a80874f1 100644
--- a/tests/test_ec2/test_spot_instances.py
+++ b/tests/test_ec2/test_spot_instances.py
@@ -257,3 +257,59 @@ def test_request_spot_instances_setting_instance_id():
request = conn.get_all_spot_instance_requests()[0]
assert request.state == "active"
assert request.instance_id == "i-12345678"
+
+
+@mock_ec2
+def test_request_spot_instances_instance_lifecycle():
+ client = boto3.client("ec2", region_name="us-east-1")
+ request = client.request_spot_instances(SpotPrice="0.5")
+
+ response = client.describe_instances()
+
+ instance = response["Reservations"][0]["Instances"][0]
+ instance["InstanceLifecycle"].should.equal("spot")
+
+
+@mock_ec2
+def test_launch_spot_instance_instance_lifecycle():
+ client = boto3.client("ec2", region_name="us-east-1")
+
+ kwargs = {
+ "KeyName": "foobar",
+ "ImageId": "ami-pytest",
+ "MinCount": 1,
+ "MaxCount": 1,
+ "InstanceType": "c4.2xlarge",
+ "TagSpecifications": [
+ {"ResourceType": "instance", "Tags": [{"Key": "key", "Value": "val"}]},
+ ],
+ "InstanceMarketOptions": {"MarketType": "spot"},
+ }
+
+ client.run_instances(**kwargs)["Instances"][0]
+
+ response = client.describe_instances()
+ instance = response["Reservations"][0]["Instances"][0]
+ instance["InstanceLifecycle"].should.equal("spot")
+
+
+@mock_ec2
+def test_launch_instance_instance_lifecycle():
+ client = boto3.client("ec2", region_name="us-east-1")
+
+ kwargs = {
+ "KeyName": "foobar",
+ "ImageId": "ami-pytest",
+ "MinCount": 1,
+ "MaxCount": 1,
+ "InstanceType": "c4.2xlarge",
+ "TagSpecifications": [
+ {"ResourceType": "instance", "Tags": [{"Key": "key", "Value": "val"}]},
+ ],
+ }
+
+ client.run_instances(**kwargs)["Instances"][0]
+
+ response = client.describe_instances()
+ instance = response["Reservations"][0]["Instances"][0]
+ instance["InstanceLifecycle"].should.equal("")