From 729e9031aa27fdc917516d01ce282435fc6d51b4 Mon Sep 17 00:00:00 2001 From: robertd Date: Mon, 2 May 2022 23:33:05 -0600 Subject: [PATCH 1/6] feat(batch): add launchTemplateId in LaunchTemplateSpecification --- .../aws-batch/lib/compute-environment.ts | 23 +- .../batch-stack.template.json | 281 ++++++++++++++++++ .../test/compute-environment.test.ts | 30 +- .../@aws-cdk/aws-batch/test/integ.batch.ts | 16 + 4 files changed, 348 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index d73643a1d6320..92619dc36a244 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -65,10 +65,18 @@ export enum AllocationStrategy { * Launch template property specification */ export interface LaunchTemplateSpecification { + /** + * The Launch template ID + * + * @default - no launch template id provided + */ + readonly launchTemplateId?: string; /** * The Launch template name + * + * @default - no launch template name provided */ - readonly launchTemplateName: string; + readonly launchTemplateName?: string; /** * The launch template version to be used (optional). * @@ -518,6 +526,19 @@ export class ComputeEnvironment extends Resource implements IComputeEnvironment throw new Error('Minimum vCpus cannot be greater than the maximum vCpus'); } } + + // Check if both launchTemplateId and launchTemplateName are provided + if (props.computeResources.launchTemplate && + (props.computeResources.launchTemplate.launchTemplateId && props.computeResources.launchTemplate.launchTemplateName)) { + throw new Error('You must specify either the launch template ID or launch template name in the request, but not both.'); + } + + // Check if both launchTemplateId and launchTemplateName are missing + if (props.computeResources.launchTemplate && + (!props.computeResources.launchTemplate.launchTemplateId && !props.computeResources.launchTemplate.launchTemplateName)) { + throw new Error('You must specify either the launch template ID or launch template name in the request.'); + } + // Setting a bid percentage is only allowed on SPOT resources + // Cannot use SPOT_CAPACITY_OPTIMIZED when using ON_DEMAND if (props.computeResources.type === ComputeResourceType.ON_DEMAND) { diff --git a/packages/@aws-cdk/aws-batch/test/batch.integ.snapshot/batch-stack.template.json b/packages/@aws-cdk/aws-batch/test/batch.integ.snapshot/batch-stack.template.json index c7a0b0b5c83aa..750db6ff3fd47 100644 --- a/packages/@aws-cdk/aws-batch/test/batch.integ.snapshot/batch-stack.template.json +++ b/packages/@aws-cdk/aws-batch/test/batch.integ.snapshot/batch-stack.template.json @@ -1002,6 +1002,281 @@ "vpcVPCGW7984C166" ] }, + "batchdemandcomputeenvlaunchtemplate2ResourceSecurityGroupBEA8DDD5": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "batch-stack/batch-demand-compute-env-launch-template-2/Resource-Security-Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "vpcA2121C38" + } + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "batchdemandcomputeenvlaunchtemplate2EcsInstanceRoleEE146754": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" + ] + ] + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "batchdemandcomputeenvlaunchtemplate2InstanceProfileC5A36CBC": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "batchdemandcomputeenvlaunchtemplate2EcsInstanceRoleEE146754" + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "batchdemandcomputeenvlaunchtemplate2ResourceServiceInstanceRole41CADAC1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "batch.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSBatchServiceRole" + ] + ] + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "batchdemandcomputeenvlaunchtemplate2E12D5CBC": { + "Type": "AWS::Batch::ComputeEnvironment", + "Properties": { + "Type": "MANAGED", + "ComputeResources": { + "AllocationStrategy": "BEST_FIT", + "InstanceRole": { + "Fn::GetAtt": [ + "batchdemandcomputeenvlaunchtemplate2InstanceProfileC5A36CBC", + "Arn" + ] + }, + "InstanceTypes": [ + "optimal" + ], + "LaunchTemplate": { + "LaunchTemplateId": { + "Ref": "ec2launchtemplate" + } + }, + "MaxvCpus": 256, + "MinvCpus": 0, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "batchdemandcomputeenvlaunchtemplate2ResourceSecurityGroupBEA8DDD5", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + ], + "Tags": { + "compute-env-tag": "123XYZ" + }, + "Type": "EC2" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "batchdemandcomputeenvlaunchtemplate2ResourceServiceInstanceRole41CADAC1", + "Arn" + ] + }, + "State": "ENABLED" + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, "batchjobqueueE3C528F2": { "Type": "AWS::Batch::JobQueue", "Properties": { @@ -1023,6 +1298,12 @@ "Ref": "batchspotcomputeenv2CE4DFD9" }, "Order": 3 + }, + { + "ComputeEnvironment": { + "Ref": "batchdemandcomputeenvlaunchtemplate2E12D5CBC" + }, + "Order": 4 } ], "Priority": 1, diff --git a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts index e25f61bd06ded..82c4ca821e7d1 100644 --- a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts +++ b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts @@ -70,7 +70,6 @@ describe('Batch Compute Environment', () => { }); }); }); - test('should deny if creating a managed environment with no provided compute resource props', () => { // THEN throws(() => { @@ -80,6 +79,35 @@ describe('Batch Compute Environment', () => { }); }); }); + test('should fail setting launch template with name and id', () => { + // THEN + throws(() => { + // WHEN + new batch.ComputeEnvironment(stack, 'test-compute-env', { + managed: true, + computeResources: { + vpc, + launchTemplate: { + launchTemplateName: 'test-template-name', + launchTemplateId: 'test-template-id', + }, + }, + }); + }); + }); + test('should fail setting launch template missing both template name or id', () => { + // THEN + throws(() => { + // WHEN + new batch.ComputeEnvironment(stack, 'test-compute-env', { + managed: true, + computeResources: { + vpc, + launchTemplate: {}, + }, + }); + }); + }); }); describe('using fargate resources', () => { test('should deny setting bid percentage', () => { diff --git a/packages/@aws-cdk/aws-batch/test/integ.batch.ts b/packages/@aws-cdk/aws-batch/test/integ.batch.ts index 4430cda4a7bf3..66371b36af69e 100644 --- a/packages/@aws-cdk/aws-batch/test/integ.batch.ts +++ b/packages/@aws-cdk/aws-batch/test/integ.batch.ts @@ -62,6 +62,22 @@ new batch.JobQueue(stack, 'batch-job-queue', { }), order: 3, }, + { + computeEnvironment: new batch.ComputeEnvironment(stack, 'batch-demand-compute-env-launch-template-2', { + managed: true, + computeResources: { + type: batch.ComputeResourceType.ON_DEMAND, + vpc, + launchTemplate: { + launchTemplateId: launchTemplate.ref as string, + }, + computeResourcesTags: { + 'compute-env-tag': '123XYZ', + }, + }, + }), + order: 4, + }, ], }); From 573cfaf6bbe8d34656287bde009e8e03b40d2d5d Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 3 May 2022 13:27:33 -0600 Subject: [PATCH 2/6] update readme --- packages/@aws-cdk/aws-batch/README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-batch/README.md b/packages/@aws-cdk/aws-batch/README.md index 67d31ea468b41..84f6c769987c1 100644 --- a/packages/@aws-cdk/aws-batch/README.md +++ b/packages/@aws-cdk/aws-batch/README.md @@ -119,7 +119,7 @@ The alternative would be to use the `BEST_FIT_PROGRESSIVE` strategy in order for Simply define your Launch Template: -```text +```ts // This example is only available in TypeScript const myLaunchTemplate = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', { launchTemplateName: 'extra-storage-template', @@ -138,7 +138,7 @@ const myLaunchTemplate = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', { }); ``` -and use it: +And provide `launchTemplateName`: ```ts declare const vpc: ec2.Vpc; @@ -155,6 +155,23 @@ const myComputeEnv = new batch.ComputeEnvironment(this, 'ComputeEnv', { }); ``` +Or provide `launchTemplateId` instead: + +```ts +declare const vpc: ec2.Vpc; +declare const myLaunchTemplate: ec2.CfnLaunchTemplate; + +const myComputeEnv = new batch.ComputeEnvironment(this, 'ComputeEnv', { + computeResources: { + launchTemplate: { + launchTemplateId: myLaunchTemplate.launchTemplateId as string, + }, + vpc, + }, + computeEnvironmentName: 'MyStorageCapableComputeEnvironment', +}); +``` + ### Importing an existing Compute Environment To import an existing batch compute environment, call `ComputeEnvironment.fromComputeEnvironmentArn()`. From 9ad8d54bf2a7b228839eab88b59d469640a14cb4 Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 3 May 2022 16:05:23 -0600 Subject: [PATCH 3/6] update readme --- packages/@aws-cdk/aws-batch/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/README.md b/packages/@aws-cdk/aws-batch/README.md index 84f6c769987c1..5ec55b9a9293e 100644 --- a/packages/@aws-cdk/aws-batch/README.md +++ b/packages/@aws-cdk/aws-batch/README.md @@ -164,7 +164,7 @@ declare const myLaunchTemplate: ec2.CfnLaunchTemplate; const myComputeEnv = new batch.ComputeEnvironment(this, 'ComputeEnv', { computeResources: { launchTemplate: { - launchTemplateId: myLaunchTemplate.launchTemplateId as string, + launchTemplateId: myLaunchTemplate.ref as string, }, vpc, }, From f627ba753c4ca13c1661986cc5e2462c8161e41c Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com> Date: Wed, 29 Jun 2022 07:11:02 -0400 Subject: [PATCH 4/6] Update packages/@aws-cdk/aws-batch/lib/compute-environment.ts --- packages/@aws-cdk/aws-batch/lib/compute-environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index 92619dc36a244..b28653a980aa1 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -66,7 +66,7 @@ export enum AllocationStrategy { */ export interface LaunchTemplateSpecification { /** - * The Launch template ID + * The Launch template ID. Mutually exclusive with `launchTemplateName`. * * @default - no launch template id provided */ From 1ef224be4dd80a70fcaaeb1efd9feb8473a958b6 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com> Date: Wed, 29 Jun 2022 07:11:07 -0400 Subject: [PATCH 5/6] Update packages/@aws-cdk/aws-batch/lib/compute-environment.ts --- packages/@aws-cdk/aws-batch/lib/compute-environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index b28653a980aa1..7038923c0eae9 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -72,7 +72,7 @@ export interface LaunchTemplateSpecification { */ readonly launchTemplateId?: string; /** - * The Launch template name + * The Launch template name. Mutually exclusive with `launchTemplateId` * * @default - no launch template name provided */ From 5907f9952baba46a1c87a69ca274f00aee0bfb91 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com> Date: Wed, 29 Jun 2022 07:12:16 -0400 Subject: [PATCH 6/6] remove comment --- packages/@aws-cdk/aws-batch/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/README.md b/packages/@aws-cdk/aws-batch/README.md index 5ec55b9a9293e..c9e8c49b3beb9 100644 --- a/packages/@aws-cdk/aws-batch/README.md +++ b/packages/@aws-cdk/aws-batch/README.md @@ -120,7 +120,6 @@ The alternative would be to use the `BEST_FIT_PROGRESSIVE` strategy in order for Simply define your Launch Template: ```ts -// This example is only available in TypeScript const myLaunchTemplate = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', { launchTemplateName: 'extra-storage-template', launchTemplateData: {