diff --git a/lib/asg-runner-stack.ts b/lib/asg-runner-stack.ts index 1fb5e22..6d841d1 100644 --- a/lib/asg-runner-stack.ts +++ b/lib/asg-runner-stack.ts @@ -290,6 +290,20 @@ export class ASGRunnerStack extends cdk.Stack implements IASGRunnerStack { this.createTagBasedResourceGroup(resourceGroupName, resourceGroupDescription, asg.autoScalingGroupName); } + // Make the ASG always launch from the launch template's newest version ($Latest) + // instead of a version number pinned at synth time. This ensures that new launches, + // scale-outs, and instance refreshes pick up the most recent launch template version + // whenever a change is deployed (or a new LT version is otherwise created). The L2 + // AutoScalingGroup pins Version to LatestVersionNumber captured at deploy time, so we + // override the CfnAutoScalingGroup's LaunchTemplate.Version to the literal "$Latest". + // Note: $Latest affects NEW instance launches; already-running instances are replaced + // by the rolling UpdatePolicy above on deploy. + const cfnAsg = asg.node.defaultChild as autoscaling.CfnAutoScalingGroup; + cfnAsg.addPropertyOverride('LaunchTemplate.LaunchTemplateId', lt.launchTemplateId); + cfnAsg.addPropertyOverride('LaunchTemplate.Version', '$Latest'); + // Remove the L2-generated LaunchTemplateName if present to avoid specifying both id and name. + cfnAsg.addPropertyDeletionOverride('LaunchTemplate.LaunchTemplateName'); + if (props.stage === ENVIRONMENT_STAGE.Beta) { new autoscaling.CfnScheduledAction(this, 'SpinDownBetaInstances', { autoScalingGroupName: asg.autoScalingGroupName, diff --git a/test/asg-runner-stack.test.ts b/test/asg-runner-stack.test.ts index a7140ca..6430879 100644 --- a/test/asg-runner-stack.test.ts +++ b/test/asg-runner-stack.test.ts @@ -120,6 +120,21 @@ describe('ASGRunnerStack test', () => { }); }); + it('references the launch template $Latest version by id (not a pinned version or name)', () => { + // The stack overrides the ASG's LaunchTemplate to reference the launch template by id + // at its $Latest version, so new launches always pick up the newest LT version rather + // than a version number pinned at synth time. + templates.forEach((template) => { + template.hasResourceProperties('AWS::AutoScaling::AutoScalingGroup', { + LaunchTemplate: { + LaunchTemplateId: Match.anyValue(), + Version: '$Latest', + LaunchTemplateName: Match.absent() + } + }); + }); + }); + it('non-dedicated-host runners keep maxCapacity equal to desired', () => { runnerConfig.runnerTypes .filter((type) => type.platform === PlatformType.AMAZONLINUX)