From ecc996620173660a36e7cde1fabca3bff6e61ace Mon Sep 17 00:00:00 2001 From: Michael Fischer Date: Tue, 11 May 2021 14:42:00 -0700 Subject: [PATCH] Updated to reflect review feedback --- packages/@aws-cdk/aws-ecs/README.md | 41 +++++---- packages/@aws-cdk/aws-ecs/lib/cluster.ts | 87 ++++++++++--------- .../@aws-cdk/aws-ecs/test/cluster.test.ts | 24 +++-- .../aws-ecs/test/ec2/ec2-service.test.ts | 4 +- .../test/ec2/integ.capacity-provider.ts | 4 +- .../test/fargate/fargate-service.test.ts | 3 +- 6 files changed, 84 insertions(+), 79 deletions(-) diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index d5ac1ed45cdf9..5e63747de137f 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -725,15 +725,19 @@ ecsService.associateCloudMapService({ ## Capacity Providers -There are two major families of Capacity Providers: [AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-capacity-providers.html) (including Fargate Spot) and EC2 [Auto -Scaling Group](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/asg-capacity-providers.html) Capacity Providers. Both are supported. +There are two major families of Capacity Providers: [AWS +Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-capacity-providers.html) +(including Fargate Spot) and EC2 [Auto Scaling +Group](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/asg-capacity-providers.html) +Capacity Providers. Both are supported. ### Fargate Capacity Providers To enable Fargate capacity providers, you can either set `enableFargateCapacityProviders` to `true` when creating your cluster, or by invoking the `enableFargateCapacityProviders()` method after creating your -cluster. This will add both `FARGATE` and `FARGATE_SPOT` as available capacity providers on your cluster. +cluster. This will add both `FARGATE` and `FARGATE_SPOT` as available capacity +providers on your cluster. ```ts const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { @@ -765,17 +769,17 @@ new ecs.FargateService(stack, 'FargateService', { ### Auto Scaling Group Capacity Providers -To add an Auto Scaling Group Capacity Provider, first create an EC2 Auto Scaling Group. Then, -create an `AsgCapacityProvider` and pass the Auto Scaling Group to it in the -constructor. Then add the Capacity Provider to the cluster. Finally, you can -refer to the Provider by its name in your service's or task's Capacity Provider -strategy. +To add an Auto Scaling Group Capacity Provider, first create an EC2 Auto Scaling +Group. Then, create an `AsgCapacityProvider` and pass the Auto Scaling Group to +it in the constructor. Then add the Capacity Provider to the cluster. Finally, +you can refer to the Provider by its name in your service's or task's Capacity +Provider strategy. -By default, an Auto Scaling Group Capacity Provider will manage the Auto Scaling Group's size -for you. It will also enable managed termination protection, in order to prevent -EC2 Auto Scaling from terminating EC2 instances that have tasks running on -them. If you want to disable this behavior, set both `enableManagedScaling` to -and `enableManagedTerminationProtection` to `false`. +By default, an Auto Scaling Group Capacity Provider will manage the Auto Scaling +Group's size for you. It will also enable managed termination protection, in +order to prevent EC2 Auto Scaling from terminating EC2 instances that have tasks +running on them. If you want to disable this behavior, set both +`enableManagedScaling` to and `enableManagedTerminationProtection` to `false`. ```ts const cluster = new ecs.Cluster(stack, 'Cluster', { @@ -790,15 +794,16 @@ const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'ASG', { maxCapacity: 100, }); -const capacityProvider = new ecs.EC2CapacityProvider(stack, 'EC2CapacityProvider', { +const capacityProvider = new ecs.AsgCapacityProvider(stack, 'AsgCapacityProvider', { autoScalingGroup, }); -cluster.addEC2CapacityProvider(capacityProvider); +cluster.addAsgCapacityProvider(capacityProvider); -const taskDefinition = new ecs.EC2TaskDefinition(stack, 'TaskDef'); +const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); taskDefinition.addContainer('web', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), memoryReservationMiB: 256, + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample', + memoryReservationMiB: 256, }); new ecs.Ec2Service(stack, 'EC2Service', { @@ -818,7 +823,7 @@ new ecs.Ec2Service(stack, 'EC2Service', { Currently, this feature is only supported for services with EC2 launch types. To add elastic inference accelerators to your EC2 instance, first add -`inferenceAccelerators` field to the EC2TaskDefinition and set the `deviceName` +`inferenceAccelerators` field to the Ec2TaskDefinition and set the `deviceName` and `deviceType` properties. ```ts diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index e93424ef6ec94..294a88fcb1858 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -119,12 +119,12 @@ export class Cluster extends Resource implements ICluster { /** * The cluster-level (FARGATE, FARGATE_SPOT) capacity providers. */ - private _clusterCapacityProviders: string[] = []; + private _fargateCapacityProviders: string[] = []; /** * The EC2 Auto Scaling Group capacity providers associated with the cluster. */ - private _ec2CapacityProviders: EC2CapacityProvider[] = []; + private _asgCapacityProviders: AsgCapacityProvider[] = []; /** * The AWS Cloud Map namespace to associate with the cluster. @@ -159,7 +159,7 @@ export class Cluster extends Resource implements ICluster { clusterSettings = [{ name: 'containerInsights', value: props.containerInsights ? ContainerInsights.ENABLED : ContainerInsights.DISABLED }]; } - this._clusterCapacityProviders = props.capacityProviders ?? []; + this._fargateCapacityProviders = props.capacityProviders ?? []; if (props.enableFargateCapacityProviders) { this.enableFargateCapacityProviders(); } @@ -167,7 +167,7 @@ export class Cluster extends Resource implements ICluster { const cluster = new CfnCluster(this, 'Resource', { clusterName: this.physicalName, clusterSettings, - capacityProviders: Lazy.list({ produce: () => this._clusterCapacityProviders }, { omitEmpty: true }), + capacityProviders: Lazy.list({ produce: () => this._fargateCapacityProviders }, { omitEmpty: true }), }); this.clusterArn = this.getResourceArnAttribute(cluster.attrArn, { @@ -193,7 +193,7 @@ export class Cluster extends Resource implements ICluster { // since it's harmless, but we'd prefer not to add unexpected new // resources to the stack which could surprise users working with // brown-field CDK apps and stacks. - Aspects.of(this).add(new MaybeCreateCapacityProviderAssociations(this, id, this._ec2CapacityProviders)); + Aspects.of(this).add(new MaybeCreateCapacityProviderAssociations(this, id, this._asgCapacityProviders)); } /** @@ -201,8 +201,8 @@ export class Cluster extends Resource implements ICluster { */ public enableFargateCapacityProviders() { for (const provider of ['FARGATE', 'FARGATE_SPOT']) { - if (!this._clusterCapacityProviders.includes(provider)) { - this._clusterCapacityProviders.push(provider); + if (!this._fargateCapacityProviders.includes(provider)) { + this._fargateCapacityProviders.push(provider); } } } @@ -247,7 +247,7 @@ export class Cluster extends Resource implements ICluster { * * Returns the AutoScalingGroup so you can add autoscaling settings to it. * - * @deprecated Use {@link Cluster.addCapacityProvider} instead. + * @deprecated Use {@link Cluster.addAsgCapacityProvider} instead. */ public addCapacity(id: string, options: AddCapacityOptions): autoscaling.AutoScalingGroup { if (options.machineImage && options.machineImageType) { @@ -273,29 +273,13 @@ export class Cluster extends Resource implements ICluster { } /** - * This method adds compute capacity to a cluster using the specified EC2 Capacity Provider. + * This method adds an Auto Scaling Group Capacity Provider to a cluster. * * @param provider the capacity provider to add to this cluster. */ - public addCapacityProvider(provider: string) { - if (!(provider === 'FARGATE' || provider === 'FARGATE_SPOT')) { - throw new Error('CapacityProvider not supported'); - } - - if (!this._clusterCapacityProviders.includes(provider)) { - this._clusterCapacityProviders.push(provider); - } - } - - /** - * This method adds an Auto Scaling Group Capacity Provider to a cluster using - * the specified EC2 Capacity Provider. - * - * @param provider the capacity provider to add to this cluster. - */ - public addEC2CapacityProvider(provider: EC2CapacityProvider, options: AddAutoScalingGroupCapacityOptions = {}) { + public addAsgCapacityProvider(provider: AsgCapacityProvider, options: AddAutoScalingGroupCapacityOptions = {}) { // Don't add the same capacity provider more than once. - if (this._ec2CapacityProviders.includes(provider)) { + if (this._asgCapacityProviders.includes(provider)) { return; } @@ -306,13 +290,13 @@ export class Cluster extends Resource implements ICluster { taskDrainTime: provider.enableManagedTerminationProtection ? Duration.seconds(0) : options.taskDrainTime, }); - this._ec2CapacityProviders.push(provider); + this._asgCapacityProviders.push(provider); } /** * This method adds compute capacity to a cluster using the specified AutoScalingGroup. * - * @deprecated Use {@link Cluster.addCapacityProvider} instead. + * @deprecated Use {@link Cluster.addAsgCapacityProvider} instead. * @param autoScalingGroup the ASG to add to this cluster. * [disable-awslint:ref-via-interface] is needed in order to install the ECS * agent by updating the ASGs user data. @@ -416,6 +400,23 @@ export class Cluster extends Resource implements ICluster { } } + /** + * This method enables the Fargate or Fargate Spot capacity providers on the cluster. + * + * @param provider the capacity provider to add to this cluster. + * @deprecated Use {@link enableFargateCapacityProviders} instead. + * @see {@link addAsgCapacityProvider} to add an Auto Scaling Group capacity provider to the cluster. + */ + public addCapacityProvider(provider: string) { + if (!(provider === 'FARGATE' || provider === 'FARGATE_SPOT')) { + throw new Error('CapacityProvider not supported'); + } + + if (!this._fargateCapacityProviders.includes(provider)) { + this._fargateCapacityProviders.push(provider); + } + } + private configureWindowsAutoScalingGroup(autoScalingGroup: autoscaling.AutoScalingGroup, options: AddAutoScalingGroupCapacityOptions = {}) { // clear the cache of the agent autoScalingGroup.addUserData('Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache'); @@ -1036,7 +1037,7 @@ enum ContainerInsights { */ export interface CapacityProviderStrategy { /** - * The name of the capacity provider + * The name of the capacity provider. */ readonly capacityProvider: string; @@ -1060,9 +1061,9 @@ capacity provider. The weight value is taken into consideration after the base v } /** - * The options for creating an EC2 Capacity Provider. + * The options for creating an Auto Scaling Group Capacity Provider. */ -export interface EC2CapacityProviderProps extends AddAutoScalingGroupCapacityOptions { +export interface AsgCapacityProviderProps extends AddAutoScalingGroupCapacityOptions { /** * The name for the capacity provider. * @@ -1112,13 +1113,13 @@ export interface EC2CapacityProviderProps extends AddAutoScalingGroupCapacityOpt } /** - * An EC2 Capacity Provider. This allows an ECS cluster to target a specific - * EC2 Auto Scaling Group for the placement of tasks. Optionally (and recommended), - * ECS can manage the number of instances in the ASG to fit the tasks, and can - * ensure that instances are not prematurely terminated while there are still tasks - * running on them. + * An Auto Scaling Group Capacity Provider. This allows an ECS cluster to target + * a specific EC2 Auto Scaling Group for the placement of tasks. Optionally (and + * recommended), ECS can manage the number of instances in the ASG to fit the + * tasks, and can ensure that instances are not prematurely terminated while + * there are still tasks running on them. */ -export class EC2CapacityProvider extends CoreConstruct { +export class AsgCapacityProvider extends CoreConstruct { /** * Capacity provider name * @default Chosen by CloudFormation @@ -1135,7 +1136,7 @@ export class EC2CapacityProvider extends CoreConstruct { */ readonly enableManagedTerminationProtection?: boolean; - constructor(scope: Construct, id: string, props: EC2CapacityProviderProps) { + constructor(scope: Construct, id: string, props: AsgCapacityProviderProps) { super(scope, id); this.autoScalingGroup = props.autoScalingGroup as autoscaling.AutoScalingGroup; @@ -1151,8 +1152,8 @@ export class EC2CapacityProvider extends CoreConstruct { name: props.capacityProviderName, autoScalingGroupProvider: { autoScalingGroupArn: this.autoScalingGroup.autoScalingGroupName, - managedScaling: { - status: props.enableManagedScaling === false ? 'DISABLED' : 'ENABLED', + managedScaling: props.enableManagedScaling === false ? undefined : { + status: 'ENABLED', targetCapacity: props.targetCapacityPercent || 100, maximumScalingStepSize: props.maximumScalingStepSize, minimumScalingStepSize: props.minimumScalingStepSize, @@ -1172,9 +1173,9 @@ export class EC2CapacityProvider extends CoreConstruct { class MaybeCreateCapacityProviderAssociations implements IAspect { private scope: CoreConstruct; private id: string; - private capacityProviders: EC2CapacityProvider[] + private capacityProviders: AsgCapacityProvider[] - constructor(scope: CoreConstruct, id: string, capacityProviders: EC2CapacityProvider[]) { + constructor(scope: CoreConstruct, id: string, capacityProviders: AsgCapacityProvider[]) { this.scope = scope; this.id = id; this.capacityProviders = capacityProviders; diff --git a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts index 0269349948554..a76c98377c1db 100644 --- a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts @@ -4,6 +4,7 @@ import { haveResource, haveResourceLike, ResourcePart, + ABSENT, } from '@aws-cdk/assert-internal'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -1809,7 +1810,7 @@ nodeunitShim({ }); // WHEN - new ecs.EC2CapacityProvider(stack, 'provider', { + new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, }); @@ -1829,7 +1830,7 @@ nodeunitShim({ test.done(); }, - 'can disable managed scaling for EC2 capacity provider'(test: Test) { + 'can disable managed scaling for ASG capacity provider'(test: Test) { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'test'); @@ -1841,7 +1842,7 @@ nodeunitShim({ }); // WHEN - new ecs.EC2CapacityProvider(stack, 'provider', { + new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, enableManagedScaling: false, }); @@ -1852,10 +1853,7 @@ nodeunitShim({ AutoScalingGroupArn: { Ref: 'asgASG4D014670', }, - ManagedScaling: { - Status: 'DISABLED', - TargetCapacity: 100, - }, + ManagedScaling: ABSENT, ManagedTerminationProtection: 'ENABLED', }, })); @@ -1874,7 +1872,7 @@ nodeunitShim({ }); // WHEN - new ecs.EC2CapacityProvider(stack, 'provider', { + new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, }); @@ -1897,7 +1895,7 @@ nodeunitShim({ }); // WHEN - new ecs.EC2CapacityProvider(stack, 'provider', { + new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, enableManagedTerminationProtection: false, }); @@ -1909,7 +1907,7 @@ nodeunitShim({ test.done(); }, - 'can add EC2 capacity via Capacity Provider'(test: Test) { + 'can add ASG capacity via Capacity Provider'(test: Test) { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'test'); @@ -1923,7 +1921,7 @@ nodeunitShim({ }); // WHEN - const capacityProvider = new ecs.EC2CapacityProvider(stack, 'provider', { + const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, enableManagedTerminationProtection: false, }); @@ -1932,8 +1930,8 @@ nodeunitShim({ cluster.enableFargateCapacityProviders(); // Ensure not added twice - cluster.addEC2CapacityProvider(capacityProvider); - cluster.addEC2CapacityProvider(capacityProvider); + cluster.addAsgCapacityProvider(capacityProvider); + cluster.addAsgCapacityProvider(capacityProvider); // THEN expect(stack).to(haveResource('AWS::ECS::ClusterCapacityProviderAssociations', { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index ee0b2b9cf0de4..c63c86cce9f65 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -250,11 +250,11 @@ nodeunitShim({ }); // WHEN - const capacityProvider = new ecs.EC2CapacityProvider(stack, 'provider', { + const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { autoScalingGroup, enableManagedTerminationProtection: false, }); - cluster.addEC2CapacityProvider(capacityProvider); + cluster.addAsgCapacityProvider(capacityProvider); const taskDefinition = new ecs.TaskDefinition(stack, 'ServerTask', { compatibility: ecs.Compatibility.EC2, diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.ts b/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.ts index 06b5f29e88437..f82ce6a9f9f56 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.capacity-provider.ts @@ -25,11 +25,11 @@ const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'ASG', { machineImage: ecs.EcsOptimizedImage.amazonLinux2(), }); -const cp = new ecs.EC2CapacityProvider(stack, 'EC2CapacityProvider', { +const cp = new ecs.AsgCapacityProvider(stack, 'EC2CapacityProvider', { autoScalingGroup, }); -cluster.addEC2CapacityProvider(cp); +cluster.addAsgCapacityProvider(cp); new ecs.Ec2Service(stack, 'EC2Service', { cluster, diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index 426f81a5e8230..a75ff256cc457 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; +import { expect, haveResource, haveResourceLike, ABSENT } from '@aws-cdk/assert-internal'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -244,6 +244,7 @@ nodeunitShim({ MinimumHealthyPercent: 50, }, // no launch type + LaunchType: ABSENT, CapacityProviderStrategy: [ { CapacityProvider: 'FARGATE_SPOT',