Skip to content

Commit 7339363

Browse files
ec2: Add AWS-managed launch template tags to EC2 instances
1 parent 196ca4c commit 7339363

2 files changed

Lines changed: 227 additions & 3 deletions

File tree

moto/ec2/models/instances.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ def __init__(
122122
tags = convert_tag_spec(tag_spec_set)
123123
instance_tags = tags.get("instance", {})
124124
self.add_tags(instance_tags)
125+
# Add AWS-managed launch template tags
126+
self.add_tags(
127+
{
128+
"aws:ec2launchtemplate:id": template_version.template.id,
129+
"aws:ec2launchtemplate:version": str(template_version.number),
130+
}
131+
)
125132

126133
self._state = InstanceState("running", 16)
127134
self._reason = ""
@@ -1098,6 +1105,6 @@ def _get_template_from_args(
10981105
template_names=[launch_template_arg["LaunchTemplateName"]]
10991106
)[0]
11001107
)
1101-
version = launch_template_arg.get("Version", template.latest_version_number)
1108+
version = launch_template_arg.get("Version", template.default_version_number)
11021109
template_version = template.get_version(version)
11031110
return template_version

tests/test_ec2/test_instances.py

Lines changed: 219 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from moto import mock_aws, settings
1515
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
1616
from moto.core.types import Base64EncodedString
17-
from tests import EXAMPLE_AMI_ID
17+
from tests import EXAMPLE_AMI_ID, allow_aws_request
1818
from tests.test_ec2 import ec2_aws_verified
1919

2020
from .helpers import assert_dryrun_error
@@ -2511,7 +2511,11 @@ def test_create_instance_from_launch_template__process_tags():
25112511
LaunchTemplate={"LaunchTemplateId": template["LaunchTemplateId"]},
25122512
)["Instances"][0]
25132513

2514-
assert instance["Tags"] == [{"Key": "k", "Value": "v"}]
2514+
assert instance["Tags"] == [
2515+
{"Key": "k", "Value": "v"},
2516+
{"Key": "aws:ec2launchtemplate:id", "Value": template["LaunchTemplateId"]},
2517+
{"Key": "aws:ec2launchtemplate:version", "Value": "1"},
2518+
]
25152519

25162520

25172521
@mock_aws
@@ -3117,3 +3121,216 @@ def test_block_device_status_conversion():
31173121

31183122
assert Instance.get_block_device_status("creating") == "creating"
31193123
assert Instance.get_block_device_status("deleting") == "deleting"
3124+
3125+
3126+
def _get_ami_id(ec2_client):
3127+
if not allow_aws_request():
3128+
# Running in mock mode - use test AMI
3129+
return EXAMPLE_AMI_ID
3130+
3131+
# Running against real AWS - get latest Amazon Linux AMI
3132+
ssm_client = boto3.client("ssm", region_name=ec2_client.meta.region_name)
3133+
kernel_61 = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64"
3134+
return ssm_client.get_parameter(Name=kernel_61)["Parameter"]["Value"]
3135+
3136+
3137+
def _create_default_launch_template(ec2_client):
3138+
template_name = str(uuid4())
3139+
ami_id = _get_ami_id(ec2_client)
3140+
return ec2_client.create_launch_template(
3141+
LaunchTemplateName=template_name,
3142+
LaunchTemplateData={
3143+
"ImageId": ami_id,
3144+
"TagSpecifications": [
3145+
{"ResourceType": "instance", "Tags": [{"Key": "k", "Value": "v1"}]}
3146+
],
3147+
},
3148+
)["LaunchTemplate"]
3149+
3150+
3151+
def _verify_instance_tags(
3152+
instance, expected_template_id, expected_template_version, expected_user_tags
3153+
):
3154+
tags = {tag["Key"]: tag["Value"] for tag in instance["Tags"]}
3155+
assert tags["aws:ec2launchtemplate:id"] == expected_template_id
3156+
assert tags["aws:ec2launchtemplate:version"] == expected_template_version
3157+
for key, value in expected_user_tags.items():
3158+
assert tags[key] == value
3159+
3160+
3161+
def _run_instance_from_template(ec2_client, template_id, version=None):
3162+
launch_template_spec = {"LaunchTemplateId": template_id}
3163+
if version:
3164+
launch_template_spec["Version"] = version
3165+
3166+
instance = ec2_client.run_instances(
3167+
MinCount=1,
3168+
MaxCount=1,
3169+
LaunchTemplate=launch_template_spec,
3170+
)["Instances"][0]
3171+
return instance
3172+
3173+
3174+
@ec2_aws_verified()
3175+
@pytest.mark.aws_verified
3176+
def test_create_instance_from_launch_template_single_template_version(ec2_client=None):
3177+
template = _create_default_launch_template(ec2_client)
3178+
template_id = template["LaunchTemplateId"]
3179+
3180+
instance = _run_instance_from_template(ec2_client, template_id)
3181+
instance_id = instance["InstanceId"]
3182+
3183+
try:
3184+
try:
3185+
_verify_instance_tags(
3186+
instance,
3187+
expected_template_id=template_id,
3188+
expected_template_version="1",
3189+
expected_user_tags={"k": "v1"},
3190+
)
3191+
finally:
3192+
# Clean up instance
3193+
ec2_client.terminate_instances(InstanceIds=[instance_id])
3194+
3195+
finally:
3196+
# Clean up launch template
3197+
ec2_client.delete_launch_template(LaunchTemplateId=template_id)
3198+
3199+
3200+
@ec2_aws_verified()
3201+
@pytest.mark.aws_verified
3202+
@pytest.mark.parametrize("version_specified", ["2", "$Latest"])
3203+
def test_create_instance_from_launch_template_latest_non_default_version(
3204+
version_specified, ec2_client=None
3205+
):
3206+
ec2_client = boto3.client("ec2", region_name="us-east-1")
3207+
ami_id = _get_ami_id(ec2_client)
3208+
3209+
template = _create_default_launch_template(ec2_client)
3210+
template_id = template["LaunchTemplateId"]
3211+
3212+
# Create a new version of the launch template with different user tags
3213+
ec2_client.create_launch_template_version(
3214+
LaunchTemplateId=template_id,
3215+
LaunchTemplateData={
3216+
"ImageId": ami_id,
3217+
"TagSpecifications": [
3218+
{"ResourceType": "instance", "Tags": [{"Key": "k", "Value": "v2"}]}
3219+
],
3220+
},
3221+
)
3222+
3223+
instance = _run_instance_from_template(
3224+
ec2_client, template_id, version=version_specified
3225+
)
3226+
instance_id = instance["InstanceId"]
3227+
3228+
try:
3229+
try:
3230+
_verify_instance_tags(
3231+
instance,
3232+
expected_template_id=template_id,
3233+
expected_template_version="2",
3234+
expected_user_tags={"k": "v2"},
3235+
)
3236+
3237+
finally:
3238+
# Clean up instance
3239+
ec2_client.terminate_instances(InstanceIds=[instance_id])
3240+
3241+
finally:
3242+
# Clean up launch template
3243+
ec2_client.delete_launch_template(LaunchTemplateId=template_id)
3244+
3245+
3246+
@ec2_aws_verified()
3247+
@pytest.mark.aws_verified
3248+
@pytest.mark.parametrize("version_specified", ["1", "$Default"])
3249+
def test_create_instance_from_launch_template_default_version(
3250+
version_specified, ec2_client=None
3251+
):
3252+
ec2_client = boto3.client("ec2", region_name="us-east-1")
3253+
ami_id = _get_ami_id(ec2_client)
3254+
3255+
template = _create_default_launch_template(ec2_client)
3256+
template_id = template["LaunchTemplateId"]
3257+
3258+
# Create a new version of the launch template with different user tags
3259+
ec2_client.create_launch_template_version(
3260+
LaunchTemplateId=template_id,
3261+
LaunchTemplateData={
3262+
"ImageId": ami_id,
3263+
"TagSpecifications": [
3264+
{"ResourceType": "instance", "Tags": [{"Key": "k", "Value": "v2"}]}
3265+
],
3266+
},
3267+
)
3268+
3269+
instance = _run_instance_from_template(
3270+
ec2_client, template_id, version=version_specified
3271+
)
3272+
instance_id = instance["InstanceId"]
3273+
3274+
try:
3275+
try:
3276+
_verify_instance_tags(
3277+
instance,
3278+
expected_template_id=template_id,
3279+
expected_template_version="1",
3280+
expected_user_tags={"k": "v1"},
3281+
)
3282+
finally:
3283+
# Clean up instance
3284+
ec2_client.terminate_instances(InstanceIds=[instance_id])
3285+
3286+
finally:
3287+
# Clean up launch template
3288+
ec2_client.delete_launch_template(LaunchTemplateId=template_id)
3289+
3290+
3291+
@ec2_aws_verified()
3292+
@pytest.mark.aws_verified
3293+
@pytest.mark.parametrize("version_specified", ["2", "$Latest", "$Default"])
3294+
def test_create_instance_from_launch_template_latest_and_default_version(
3295+
version_specified, ec2_client=None
3296+
):
3297+
ec2_client = boto3.client("ec2", region_name="us-east-1")
3298+
ami_id = _get_ami_id(ec2_client)
3299+
3300+
template = _create_default_launch_template(ec2_client)
3301+
template_id = template["LaunchTemplateId"]
3302+
3303+
# Create a new version of the launch template with different user tags
3304+
ec2_client.create_launch_template_version(
3305+
LaunchTemplateId=template_id,
3306+
LaunchTemplateData={
3307+
"ImageId": ami_id,
3308+
"TagSpecifications": [
3309+
{"ResourceType": "instance", "Tags": [{"Key": "k", "Value": "v2"}]}
3310+
],
3311+
},
3312+
)
3313+
3314+
# Set the default version to be the second version, so that both $Latest and $Default point to the same version
3315+
ec2_client.modify_launch_template(LaunchTemplateId=template_id, DefaultVersion="2")
3316+
3317+
instance = _run_instance_from_template(
3318+
ec2_client, template_id, version=version_specified
3319+
)
3320+
instance_id = instance["InstanceId"]
3321+
3322+
try:
3323+
try:
3324+
_verify_instance_tags(
3325+
instance,
3326+
expected_template_id=template_id,
3327+
expected_template_version="2",
3328+
expected_user_tags={"k": "v2"},
3329+
)
3330+
finally:
3331+
# Clean up instance
3332+
ec2_client.terminate_instances(InstanceIds=[instance_id])
3333+
3334+
finally:
3335+
# Clean up launch template
3336+
ec2_client.delete_launch_template(LaunchTemplateId=template_id)

0 commit comments

Comments
 (0)