@@ -3158,15 +3158,28 @@ def _verify_instance_tags(
31583158 assert tags [key ] == value
31593159
31603160
3161- def _run_instance_from_template (ec2_client , template_id , version = None ):
3162- launch_template_spec = {"LaunchTemplateId" : template_id }
3161+ def _run_instance_from_template (
3162+ ec2_client ,
3163+ template_id = None ,
3164+ template_name = None ,
3165+ version = None ,
3166+ ** instance_kwargs ,
3167+ ):
3168+ launch_template_spec = {}
3169+ if template_id :
3170+ launch_template_spec ["LaunchTemplateId" ] = template_id
3171+ elif template_name :
3172+ launch_template_spec ["LaunchTemplateName" ] = template_name
3173+ else :
3174+ raise ValueError ("Either template_id or template_name must be provided." )
31633175 if version :
31643176 launch_template_spec ["Version" ] = version
31653177
31663178 instance = ec2_client .run_instances (
31673179 MinCount = 1 ,
31683180 MaxCount = 1 ,
31693181 LaunchTemplate = launch_template_spec ,
3182+ ** instance_kwargs ,
31703183 )["Instances" ][0 ]
31713184 return instance
31723185
@@ -3334,3 +3347,201 @@ def test_create_instance_from_launch_template_latest_and_default_version(
33343347 finally :
33353348 # Clean up launch template
33363349 ec2_client .delete_launch_template (LaunchTemplateId = template_id )
3350+
3351+
3352+ _LT_USER_DATA_SCRIPT = b"#!/bin/bash\n echo from-template"
3353+ _LT_USER_DATA_B64 = base64 .b64encode (_LT_USER_DATA_SCRIPT ).decode ()
3354+
3355+
3356+ @ec2_aws_verified (
3357+ create_launch_template = True ,
3358+ launch_template_data = {"InstanceType" : "t2.micro" , "UserData" : _LT_USER_DATA_B64 },
3359+ )
3360+ @pytest .mark .aws_verified
3361+ def test_run_instances__user_data_from_launch_template (
3362+ ec2_client = None , launch_template_name = None
3363+ ):
3364+ """UserData in a launch template is applied when not supplied in RunInstances."""
3365+ ami_id = _get_ami_id (ec2_client )
3366+ instance = _run_instance_from_template (
3367+ ec2_client , template_name = launch_template_name , ImageId = ami_id
3368+ )
3369+ instance_id = instance ["InstanceId" ]
3370+ try :
3371+ attr = ec2_client .describe_instance_attribute (
3372+ InstanceId = instance_id , Attribute = "userData"
3373+ )
3374+ assert attr ["UserData" ]["Value" ] == _LT_USER_DATA_B64
3375+ finally :
3376+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3377+
3378+
3379+ @ec2_aws_verified (
3380+ create_launch_template = True ,
3381+ launch_template_data = {"InstanceType" : "t2.micro" , "UserData" : _LT_USER_DATA_B64 },
3382+ )
3383+ @pytest .mark .aws_verified
3384+ def test_run_instances__user_data_override_takes_priority (
3385+ ec2_client = None , launch_template_name = None
3386+ ):
3387+ """Explicit UserData in RunInstances overrides the launch template value."""
3388+ ami_id = _get_ami_id (ec2_client )
3389+ request_script = "#!/bin/bash\n echo from-request"
3390+ expected_b64 = base64 .b64encode (request_script .encode ()).decode ()
3391+
3392+ instance = _run_instance_from_template (
3393+ ec2_client ,
3394+ template_name = launch_template_name ,
3395+ ImageId = ami_id ,
3396+ UserData = request_script ,
3397+ )
3398+ instance_id = instance ["InstanceId" ]
3399+ try :
3400+ attr = ec2_client .describe_instance_attribute (
3401+ InstanceId = instance_id , Attribute = "userData"
3402+ )
3403+ assert attr ["UserData" ]["Value" ] == expected_b64
3404+ finally :
3405+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3406+
3407+
3408+ @ec2_aws_verified (
3409+ create_launch_template = True ,
3410+ launch_template_data = {"InstanceType" : "t2.micro" },
3411+ )
3412+ @pytest .mark .aws_verified
3413+ def test_run_instances__instance_type_from_launch_template (
3414+ ec2_client = None , launch_template_name = None
3415+ ):
3416+ """InstanceType in a launch template is applied when not supplied in RunInstances."""
3417+ ami_id = _get_ami_id (ec2_client )
3418+ instance = _run_instance_from_template (
3419+ ec2_client , template_name = launch_template_name , ImageId = ami_id
3420+ )
3421+ instance_id = instance ["InstanceId" ]
3422+ try :
3423+ assert instance ["InstanceType" ] == "t2.micro"
3424+ attr = ec2_client .describe_instance_attribute (
3425+ InstanceId = instance_id , Attribute = "instanceType"
3426+ )
3427+ assert attr ["InstanceType" ]["Value" ] == "t2.micro"
3428+ describe_instances = ec2_client .describe_instances (InstanceIds = [instance_id ])
3429+ assert (
3430+ describe_instances ["Reservations" ][0 ]["Instances" ][0 ]["InstanceType" ]
3431+ == "t2.micro"
3432+ )
3433+ finally :
3434+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3435+
3436+
3437+ @ec2_aws_verified (
3438+ create_launch_template = True ,
3439+ launch_template_data = {"InstanceType" : "t2.micro" },
3440+ )
3441+ @pytest .mark .aws_verified
3442+ def test_run_instances__instance_type_override_takes_priority (
3443+ ec2_client = None , launch_template_name = None
3444+ ):
3445+ """Explicit InstanceType in RunInstances overrides the launch template value."""
3446+ ami_id = _get_ami_id (ec2_client )
3447+ resp = ec2_client .run_instances (
3448+ MinCount = 1 ,
3449+ MaxCount = 1 ,
3450+ ImageId = ami_id ,
3451+ LaunchTemplate = {"LaunchTemplateName" : launch_template_name },
3452+ InstanceType = "t2.small" ,
3453+ )
3454+ instance_id = resp ["Instances" ][0 ]["InstanceId" ]
3455+ try :
3456+ assert resp ["Instances" ][0 ]["InstanceType" ] == "t2.small"
3457+ attr = ec2_client .describe_instance_attribute (
3458+ InstanceId = instance_id , Attribute = "instanceType"
3459+ )
3460+ assert attr ["InstanceType" ]["Value" ] == "t2.small"
3461+ describe_instances = ec2_client .describe_instances (InstanceIds = [instance_id ])
3462+ assert (
3463+ describe_instances ["Reservations" ][0 ]["Instances" ][0 ]["InstanceType" ]
3464+ == "t2.small"
3465+ )
3466+ finally :
3467+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3468+
3469+
3470+ @ec2_aws_verified ()
3471+ @pytest .mark .aws_verified
3472+ def test_run_instances__key_name_from_launch_template (ec2_client = None ):
3473+ """KeyName in a launch template is applied when not supplied in RunInstances."""
3474+ ami_id = _get_ami_id (ec2_client )
3475+ key_name = f"test-key-{ str (uuid4 ())[0 :8 ]} "
3476+ lt_name = str (uuid4 ())
3477+ ec2_client .create_key_pair (KeyName = key_name )
3478+ ec2_client .create_launch_template (
3479+ LaunchTemplateName = lt_name ,
3480+ LaunchTemplateData = {"InstanceType" : "t2.micro" , "KeyName" : key_name },
3481+ )
3482+ instance = _run_instance_from_template (
3483+ ec2_client , template_name = lt_name , ImageId = ami_id
3484+ )
3485+ instance_id = instance ["InstanceId" ]
3486+ try :
3487+ assert instance ["KeyName" ] == key_name
3488+ describe_instances = ec2_client .describe_instances (InstanceIds = [instance_id ])
3489+ assert (
3490+ describe_instances ["Reservations" ][0 ]["Instances" ][0 ]["KeyName" ] == key_name
3491+ )
3492+ finally :
3493+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3494+ ec2_client .delete_launch_template (LaunchTemplateName = lt_name )
3495+ ec2_client .delete_key_pair (KeyName = key_name )
3496+
3497+
3498+ @ec2_aws_verified ()
3499+ @pytest .mark .aws_verified
3500+ def test_run_instances__security_group_ids_from_launch_template (ec2_client = None ):
3501+ """SecurityGroupIds in a launch template are applied when not supplied in RunInstances."""
3502+ ami_id = _get_ami_id (ec2_client )
3503+ vpc_id = ec2_client .create_vpc (CidrBlock = "10.0.0.0/16" )["Vpc" ]["VpcId" ]
3504+ subnet_id = ec2_client .create_subnet (
3505+ VpcId = vpc_id ,
3506+ CidrBlock = "10.0.1.0/24" ,
3507+ AvailabilityZone = ec2_client .meta .region_name + "a" ,
3508+ )["Subnet" ]["SubnetId" ]
3509+ sg_id = ec2_client .create_security_group (
3510+ GroupName = f"test-sg-{ str (uuid4 ())[0 :6 ]} " ,
3511+ Description = "test" ,
3512+ VpcId = vpc_id ,
3513+ )["GroupId" ]
3514+ lt_name = str (uuid4 ())
3515+ ec2_client .create_launch_template (
3516+ LaunchTemplateName = lt_name ,
3517+ LaunchTemplateData = {
3518+ "InstanceType" : "t2.micro" ,
3519+ "SecurityGroupIds" : [sg_id ],
3520+ },
3521+ )
3522+ instance = _run_instance_from_template (
3523+ ec2_client , template_name = lt_name , ImageId = ami_id , SubnetId = subnet_id
3524+ )
3525+ instance_id = instance ["InstanceId" ]
3526+ try :
3527+ instance_sg_ids = [g ["GroupId" ] for g in instance ["SecurityGroups" ]]
3528+ assert sg_id in instance_sg_ids
3529+ attr = ec2_client .describe_instance_attribute (
3530+ InstanceId = instance_id , Attribute = "groupSet"
3531+ )
3532+ attr_sg_ids = [g ["GroupId" ] for g in attr ["Groups" ]]
3533+ assert sg_id in attr_sg_ids
3534+ describe_instances = ec2_client .describe_instances (InstanceIds = [instance_id ])
3535+ instance_sg_ids = [
3536+ g ["GroupId" ]
3537+ for g in describe_instances ["Reservations" ][0 ]["Instances" ][0 ][
3538+ "SecurityGroups"
3539+ ]
3540+ ]
3541+ assert sg_id in instance_sg_ids
3542+ finally :
3543+ ec2_client .terminate_instances (InstanceIds = [instance_id ])
3544+ ec2_client .delete_launch_template (LaunchTemplateName = lt_name )
3545+ ec2_client .delete_security_group (GroupId = sg_id )
3546+ ec2_client .delete_subnet (SubnetId = subnet_id )
3547+ ec2_client .delete_vpc (VpcId = vpc_id )
0 commit comments