diff --git a/moto/ec2/models.py b/moto/ec2/models.py index ef512d80f..44a9f2b2a 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -572,7 +572,24 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel): self.ec2_backend = ec2_backend self.id = random_instance_id() self.lifecycle = kwargs.get("lifecycle") - self.image_id = image_id + + launch_template_arg = kwargs.get("launch_template", {}) + if launch_template_arg and not image_id: + # the image id from the template should be used + template = ( + ec2_backend.describe_launch_templates( + template_ids=[launch_template_arg["LaunchTemplateId"]] + )[0] + if "LaunchTemplateId" in launch_template_arg + else ec2_backend.describe_launch_templates( + template_names=[launch_template_arg["LaunchTemplateName"]] + )[0] + ) + version = launch_template_arg.get("Version", template.latest_version_number) + self.image_id = template.get_version(int(version)).image_id + else: + self.image_id = image_id + self._state = InstanceState("running", 16) self._reason = "" self._state_reason = StateReason() @@ -600,7 +617,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel): # If we are in EC2-Classic, autoassign a public IP self.associate_public_ip = True - amis = self.ec2_backend.describe_images(filters={"image-id": image_id}) + amis = self.ec2_backend.describe_images(filters={"image-id": self.image_id}) ami = amis[0] if amis else None if ami is None: warnings.warn( @@ -608,7 +625,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel): "in the near future this will " "cause an error.\n" "Use ec2_backend.describe_images() to " - "find suitable image for your test".format(image_id), + "find suitable image for your test".format(self.image_id), PendingDeprecationWarning, ) diff --git a/moto/ec2/responses/instances.py b/moto/ec2/responses/instances.py index cb0633ee5..3fd8dd53c 100644 --- a/moto/ec2/responses/instances.py +++ b/moto/ec2/responses/instances.py @@ -69,6 +69,7 @@ class InstanceResponse(BaseResponse): "instance_initiated_shutdown_behavior": self._get_param( "InstanceInitiatedShutdownBehavior" ), + "launch_template": self._get_multi_param_dict("LaunchTemplate"), } mappings = self._parse_block_device_mapping() diff --git a/tests/test_ec2/test_instances.py b/tests/test_ec2/test_instances.py index 0723a944e..b9d539090 100644 --- a/tests/test_ec2/test_instances.py +++ b/tests/test_ec2/test_instances.py @@ -2931,3 +2931,30 @@ def test_instance_lifecycle(): instance = result[0] assert instance.instance_lifecycle is None + + +@mock_ec2 +@pytest.mark.parametrize( + "launch_template_kind", ("LaunchTemplateId", "LaunchTemplateName") +) +def test_create_instance_with_launch_template_id_produces_no_warning( + launch_template_kind, +): + client, resource = ( + boto3.client("ec2", region_name="us-west-1"), + boto3.resource("ec2", region_name="us-west-1"), + ) + + template = client.create_launch_template( + LaunchTemplateName="test-template", + LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID}, + )["LaunchTemplate"] + + with pytest.warns(None) as captured_warnings: + resource.create_instances( + MinCount=1, + MaxCount=1, + LaunchTemplate={launch_template_kind: template[launch_template_kind]}, + ) + + assert len(captured_warnings) == 0