Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(autoscaling): Auto Scaling Group with Launch Template #19066

Merged
merged 11 commits into from
Apr 13, 2022

Conversation

Martin1994
Copy link
Contributor

Add support to launch an Auto Scaling Group from a Launch Template rather than a launch configuration.

Closes #6734.


High level designs:

The current AutoScalingGroup L2 construct, unfortunately, is deeply coupled with LaunchConfiguration. Therefore adding LaunchTemplate to the existing construct is not trivial.

There are two different approaches to support LaunchTemplate:

  1. Implement another brand new L2 construct with IAutoScalingGroup interface. The shared logic between the old and the new one such as adding scaling policies can be extracted to a common parent class.
  2. Add LaunchTemplate related interface to the existing L2 construct with minimum breaking changes.

Adding a new construct is always guaranteed to be a clean solution code-wise, but it can also cause confusion from the end user about scattered CDK implementation on the same CFN resource, and on the other hand breaks the existing libraries consuming the existing AutoScalingGroup construct rather than the IAutoScalingGroup interface.

Adding LT to the existing construct, as what this PR does, however may change the API behaviour when LT is used. For example, the implementation in this PR turns AutoScalingGroup.connections from a public field to a public getter, and will throw an error when the ASG is created from a LT reference, which means existing libraries taking an AutoScalingGroup instance as an IConnectable will get runtime error in this case. Existing code (i.e. ASG created from the L2 construct with a LC rather than a LT) won't break with this change.

This PR picks the latter approach since I believe it provides a better experience overall, mainly because of its continuity.


BREAKING CHANGE: Properties relying on a launch configuration are now either optional or turned into throwable getters

  • autoscaling: AutoScalingGroupProps.instanceType is now optional
  • autoscaling: AutoScalingGroupProps.machineImage is now optional
  • autoscaling: AutoScalingGroup.connections is now a throwable getter
  • autoscaling: AutoScalingGroup.role is now a throwable getter
  • autoscaling: AutoScalingGroup.userData is now a throwable getter

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Feb 21, 2022

@github-actions github-actions bot added the @aws-cdk/aws-autoscaling Related to Amazon EC2 Auto Scaling label Feb 21, 2022
@rix0rrr rix0rrr added feature-request A feature should be added or improved. p1 and removed p1 feature-request A feature should be added or improved. @aws-cdk/aws-autoscaling Related to Amazon EC2 Auto Scaling labels Mar 4, 2022
@jbrown2w
Copy link

Actually being able to use Launch Templates would be neat.

@jungseoklee
Copy link
Contributor

The approach looks reasonable. As mentioned, this won't break existing LC users, which is what I like.

*
* https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-purchase-options.html
*/
export interface MixedInstancesPolicy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if it is better to have a separate file for mixed instance policy because this file is getting bigger.

@@ -1315,6 +1625,74 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements
metrics: group._metrics?.size !== 0 ? [...group._metrics].map(m => m.name) : undefined,
}));
}

private getLaunchSettings(launchConfig?: CfnLaunchConfiguration, launchTemplate?: ec2.ILaunchTemplate, mixedInstancesPolicy?: MixedInstancesPolicy)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if it is better to have a separate file for launch template and launch configuration because this file is getting bigger.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure how practical it is since this design puts LC and LT under one single class, and I don't think we can break a class definition into multiple files like partial class in C#.

@jungseoklee
Copy link
Contributor

Can we get attention from maintainers? I see more than 100 thumbs up for this feature, so it would be great if we can start reviewing this PR.

Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good first attempt! We're a few iterations from merging this in, but this is looking great so far.

packages/@aws-cdk/aws-autoscaling/README.md Outdated Show resolved Hide resolved
Comment on lines 65 to 66
declare const lt1: ec2.LaunchTemplate;
declare const lt2: ec2.LaunchTemplate;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we call these launchTemplate1 and launchTemplate2?

/**
* Type of instance to launch
*
* Launch template must not be specified when this property is specified.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be launchTemplate must not be specified when this property is specified.

Comment on lines 1476 to 1478
/**
* UserData for the instances
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we improve this comment to explain what the UserData does and how it is used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can borrow some words from the public doc. However more importantly I think it's better to document the fact that this getter can throw error. Same as the role getter.

/**
* UserData for the instances
*/
public readonly userData: ec2.UserData;

Comment on lines 1491 to 1493
/**
* Role for the instances
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update this comment to explain what this Role is used for? eg if it's an execution role, that should be mentioned here (also, this variable probably needs a better name than role; perhaps executionRole or instanceExecutionRole, if that's what it represents).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot change the getter name here (same as userData) because it was a class property with the same name. role and userData are turned into getters so that they can throw exceptions when a Launch Template reference is given.

/**
* The IAM role assumed by instances of this fleet.
*/
public readonly role: iam.IRole;

@mergify mergify bot dismissed comcalvi’s stale review March 31, 2022 06:48

Pull request has been modified.

@Martin1994
Copy link
Contributor Author

Any update?

Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking better! In general, when a PR is ready for review, please re-request the review on github

Comment on lines 1205 to 1207
if (props.mixedInstancesPolicy && props.mixedInstancesPolicy.launchTemplate instanceof ec2.LaunchTemplate) {
this.launchTemplate = props.mixedInstancesPolicy.launchTemplate;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this to a local variable?

Comment on lines 1172 to 1178
if (props.launchTemplate && props.launchTemplate instanceof ec2.LaunchTemplate) {
this.launchTemplate = props.launchTemplate;
}

launchConfig.node.addDependency(this.role);
if (props.mixedInstancesPolicy && props.mixedInstancesPolicy.launchTemplate instanceof ec2.LaunchTemplate) {
this.launchTemplate = props.mixedInstancesPolicy.launchTemplate;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code:

      vpc: new ec2.Vpc(this, 'template-vpc'),
      mixedInstancesPolicy: {
        launchTemplate: new ec2.LaunchTemplate(this, 'template-mixed', {
          instanceType: new ec2.InstanceType('a1.2xlarge')
        })
      }
    });

Results in a deploy time error:

You must use a valid fully-formed launch template. The request must contain the parameter ImageId (Service: AmazonAutoScaling; Status Code: 400; Error Code: ValidationError;

This error only happens if the launch template is specified here as part of an autoscaling group, and does not happen when a launch template is specified on its own; thus, we should ensure the user has passed an imageId here, and throw if they have not.


expect(() => {
asg.connections;
}).toThrow();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we validate that the error thrown here at least partially matches the error message?

@mergify mergify bot dismissed comcalvi’s stale review April 12, 2022 02:56

Pull request has been modified.

Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty much perfect, just one small comment.

@mergify mergify bot dismissed comcalvi’s stale review April 13, 2022 00:07

Pull request has been modified.

@robertd
Copy link
Contributor

robertd commented Apr 13, 2022

Thanks for all the hard work you’ve put in on this PR @Martin1994 🙌

@Martin1994
Copy link
Contributor Author

Just to confirm, GitHub can rebase, squash and merge this PR right?

@robertd
Copy link
Contributor

robertd commented Apr 13, 2022

@Martin1994 Once @comcalvi approves this PR GitHub Actions will do all the grunt work.

comcalvi
comcalvi previously approved these changes Apr 13, 2022
Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work @Martin1994!

@mergify
Copy link
Contributor

mergify bot commented Apr 13, 2022

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@robertd
Copy link
Contributor

robertd commented Apr 13, 2022

Very excited for this PR!!! Thanks everyone. 🙏

@jungseoklee
Copy link
Contributor

Very excited. Great thanks, everyone!

@mergify mergify bot dismissed comcalvi’s stale review April 13, 2022 20:22

Pull request has been modified.

@robertd
Copy link
Contributor

robertd commented Apr 13, 2022

Thanks for stepping in @comcalvi 🙌

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: ee7860c
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify
Copy link
Contributor

mergify bot commented Apr 13, 2022

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit 1581af0 into aws:master Apr 13, 2022
@badfun
Copy link
Contributor

badfun commented Apr 14, 2022

@Martin1994 hurray! Thanks for this. Looking forward to refactoring. 🙌

StevePotter pushed a commit to StevePotter/aws-cdk that referenced this pull request Apr 27, 2022
Add support to launch an Auto Scaling Group from a Launch Template rather than a launch configuration.

Closes aws#6734.

----

High level designs:

The current AutoScalingGroup L2 construct, unfortunately, is deeply coupled with LaunchConfiguration. Therefore adding LaunchTemplate to the existing construct is not trivial.

There are two different approaches to support LaunchTemplate:
1. Implement another brand new L2 construct with `IAutoScalingGroup` interface. The shared logic between the old and the new one such as adding scaling policies can be extracted to a common parent class.
2. Add LaunchTemplate related interface to the existing L2 construct with minimum breaking changes.

Adding a new construct is always guaranteed to be a clean solution code-wise, but it can also cause confusion from the end user about scattered CDK implementation on the same CFN resource, and on the other hand breaks the existing libraries consuming the existing `AutoScalingGroup` construct rather than the `IAutoScalingGroup` interface.

Adding LT to the existing construct, as what this PR does, however may change the API behaviour when LT is used. For example, the implementation in this PR turns `AutoScalingGroup.connections` from a public field to a public getter, and will throw an error when the ASG is created from a LT reference, which means existing libraries taking an `AutoScalingGroup` instance as an `IConnectable` will get runtime error in this case. Existing code (i.e. ASG created from the L2 construct with a LC rather than a LT) won't break with this change.

This PR picks the latter approach since I believe it provides a better experience overall, mainly because of its continuity.

----

BREAKING CHANGE: Properties relying on a launch configuration are now either optional or turned into throwable getters
  * **autoscaling:** `AutoScalingGroupProps.instanceType` is now optional
  * **autoscaling:** `AutoScalingGroupProps.machineImage` is now optional
  * **autoscaling:** `AutoScalingGroup.connections` is now a throwable getter
  * **autoscaling:** `AutoScalingGroup.role` is now a throwable getter
  * **autoscaling:** `AutoScalingGroup.userData` is now a throwable getter

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved. p1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for Launch Templates
8 participants