diff --git a/docs/DESIGN_GUIDELINES.md b/docs/DESIGN_GUIDELINES.md index 209875ef1279a..7e380dda67efb 100644 --- a/docs/DESIGN_GUIDELINES.md +++ b/docs/DESIGN_GUIDELINES.md @@ -1523,6 +1523,27 @@ information that can be obtained from the stack trace. * Do not use FnSub +### Lazys + +Do not use a `Lazy` to perform a mutation on the construct tree. For example: + +```ts +constructor(scope: Scope, id: string, props: MyConstructProps) { + this.lazyProperty = Lazy.any({ + produce: () => { + return props.logging.bind(this, this); + }, + }); +} +``` + +`bind()` methods mutate the construct tree, and should not be called from a callback +in a `Lazy`. + +* The why: + - `Lazy`s are called after the construct tree has already been sythesized. Mutating it + at this point could have not-obvious consequences. + ## Documentation Documentation style (copy from official AWS docs) No need to Capitalize Resource diff --git a/packages/@aws-cdk/aws-batch-alpha/lib/ecs-container-definition.ts b/packages/@aws-cdk/aws-batch-alpha/lib/ecs-container-definition.ts index fb6124569828e..c36b94f2876d0 100644 --- a/packages/@aws-cdk/aws-batch-alpha/lib/ecs-container-definition.ts +++ b/packages/@aws-cdk/aws-batch-alpha/lib/ecs-container-definition.ts @@ -2,7 +2,7 @@ import * as ecs from 'aws-cdk-lib/aws-ecs'; import { IFileSystem } from 'aws-cdk-lib/aws-efs'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; -import { DefaultTokenResolver, Lazy, PhysicalName, Size, StringConcat, Tokenization } from 'aws-cdk-lib'; +import { Lazy, PhysicalName, Size } from 'aws-cdk-lib'; import { Construct, IConstruct } from 'constructs'; import { CfnJobDefinition } from 'aws-cdk-lib/aws-batch'; import { LinuxParameters } from './linux-parameters'; @@ -237,6 +237,7 @@ export interface HostVolumeOptions extends EcsVolumeOptions { */ readonly hostPath?: string; } + /** * Creates a Host volume. This volume will persist on the host at the specified `hostPath`. * If the `hostPath` is not specified, Docker will choose the host path. In this case, @@ -306,6 +307,13 @@ export interface IEcsContainerDefinition extends IConstruct { */ readonly environment?: { [key:string]: string }; + /** + * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. + * + * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html + */ + readonly executionRole: iam.IRole; + /** * The role that the container can assume. * @@ -411,6 +419,15 @@ export interface EcsContainerDefinitionProps { */ readonly environment?: { [key:string]: string }; + /** + * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. + * + * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html + * + * @default - a Role will be created + */ + readonly executionRole?: iam.IRole; + /** * The role that the container can assume. * @@ -474,6 +491,7 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta public readonly memory: Size; public readonly command?: string[]; public readonly environment?: { [key:string]: string }; + public readonly executionRole: iam.IRole; public readonly jobRole?: iam.IRole; public readonly linuxParameters?: LinuxParameters; public readonly logDriverConfig?: ecs.LogDriverConfig; @@ -482,8 +500,6 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta public readonly user?: string; public readonly volumes: EcsVolume[]; - public abstract readonly executionRole?: iam.IRole; - private readonly imageConfig: ecs.ContainerImageConfig; constructor(scope: Construct, id: string, props: EcsContainerDefinitionProps) { @@ -493,41 +509,32 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta this.cpu = props.cpu; this.command = props.command; this.environment = props.environment; + this.executionRole = props.executionRole ?? createExecutionRole(this, 'ExecutionRole'); this.jobRole = props.jobRole; this.linuxParameters = props.linuxParameters; this.memory = props.memory; - // Lazy so this.executionRole can be filled by subclasses - this.logDriverConfig = Lazy.any({ - produce: () => { - if (props.logging) { - return props.logging.bind(this, { - ...this as any, - // TS! - taskDefinition: { - obtainExecutionRole: () => this.executionRole, - }, - }); - } - - return undefined; - }, - }) as any; + if (props.logging) { + this.logDriverConfig = props.logging.bind(this, { + ...this as any, + // TS! + taskDefinition: { + obtainExecutionRole: () => this.executionRole, + }, + }); + } this.readonlyRootFilesystem = props.readonlyRootFilesystem ?? false; this.secrets = props.secrets; this.user = props.user; this.volumes = props.volumes ?? []; - // Lazy so this.executionRole can be filled by subclasses - this.imageConfig = Lazy.any({ - produce: () => props.image.bind(this, { - ...this as any, - taskDefinition: { - obtainExecutionRole: () => this.executionRole, - }, - }), - }) as any; + this.imageConfig = props.image.bind(this, { + ...this as any, + taskDefinition: { + obtainExecutionRole: () => this.executionRole, + }, + }); } /** @@ -535,10 +542,7 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta */ public _renderContainerDefinition(): CfnJobDefinition.ContainerPropertiesProperty { return { - image: Tokenization.resolve(this.imageConfig, { - scope: this, - resolver: new DefaultTokenResolver(new StringConcat()), - }).imageName, + image: this.imageConfig.imageName, command: this.command, environment: Object.keys(this.environment ?? {}).map((envKey) => ({ name: envKey, @@ -792,15 +796,6 @@ export interface EcsEc2ContainerDefinitionProps extends EcsContainerDefinitionPr * @default - no gpus */ readonly gpu?: number; - - /** - * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. - * - * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html - * - * @default - a Role will be created if logging is specified, no role otherwise - */ - readonly executionRole?: iam.IRole; } /** @@ -811,21 +806,11 @@ export class EcsEc2ContainerDefinition extends EcsContainerDefinitionBase implem public readonly ulimits: Ulimit[]; public readonly gpu?: number; - /** - * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. - * - * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html - * - * @default - a Role will be created if logging is specified, no role otherwise - */ - public readonly executionRole?: iam.IRole; - constructor(scope: Construct, id: string, props: EcsEc2ContainerDefinitionProps) { super(scope, id, props); this.privileged = props.privileged; this.ulimits = props.ulimits ?? []; this.gpu = props.gpu; - this.executionRole = props.executionRole ?? (this.logDriverConfig ? createExecutionRole(this, 'ExecutionRole') : undefined); } /** @@ -919,15 +904,6 @@ export interface EcsFargateContainerDefinitionProps extends EcsContainerDefiniti * @default LATEST */ readonly fargatePlatformVersion?: ecs.FargatePlatformVersion; - - /** - * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. - * - * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html - * - * @default - a Role will be created - */ - readonly executionRole?: iam.IRole; } /** @@ -937,20 +913,10 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im public readonly fargatePlatformVersion?: ecs.FargatePlatformVersion; public readonly assignPublicIp?: boolean; - /** - * The role used by Amazon ECS container and AWS Fargate agents to make AWS API calls on your behalf. - * - * @see https://docs.aws.amazon.com/batch/latest/userguide/execution-IAM-role.html - * - * @default - a Role will be created - */ - public readonly executionRole: iam.IRole; - constructor(scope: Construct, id: string, props: EcsFargateContainerDefinitionProps) { super(scope, id, props); this.assignPublicIp = props.assignPublicIp; this.fargatePlatformVersion = props.fargatePlatformVersion; - this.executionRole = props.executionRole ?? createExecutionRole(this, 'ExecutionRole'); } /** diff --git a/packages/@aws-cdk/aws-batch-alpha/test/ecs-container-definition.test.ts b/packages/@aws-cdk/aws-batch-alpha/test/ecs-container-definition.test.ts index 3861117ead57a..43ed3212aeb89 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/ecs-container-definition.test.ts +++ b/packages/@aws-cdk/aws-batch-alpha/test/ecs-container-definition.test.ts @@ -3,6 +3,7 @@ import { Template } from 'aws-cdk-lib/assertions'; import * as path from 'path'; import { Vpc } from 'aws-cdk-lib/aws-ec2'; import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as ecr from 'aws-cdk-lib/aws-ecr'; import * as efs from 'aws-cdk-lib/aws-efs'; import { ArnPrincipal, Role } from 'aws-cdk-lib/aws-iam'; import * as logs from 'aws-cdk-lib/aws-logs'; @@ -11,6 +12,7 @@ import { Size, Stack } from 'aws-cdk-lib'; import { EcsContainerDefinitionProps, EcsEc2ContainerDefinition, EcsFargateContainerDefinition, EcsJobDefinition, EcsVolume, IEcsEc2ContainerDefinition, LinuxParameters, UlimitName } from '../lib'; import { CfnJobDefinitionProps } from 'aws-cdk-lib/aws-batch'; import { capitalizePropertyNames } from './utils'; +import { DockerImageAsset } from 'aws-cdk-lib/aws-ecr-assets'; // GIVEN const defaultContainerProps: EcsContainerDefinitionProps = { @@ -528,6 +530,85 @@ describe.each([EcsEc2ContainerDefinition, EcsFargateContainerDefinition])('%p', }, }); }); + + test('correctly renders docker images', () => { + // WHEN + new EcsJobDefinition(stack, 'ECSJobDefn', { + container: new ContainerDefinition(stack, 'EcsContainer', { + ...defaultContainerProps, + image: ecs.ContainerImage.fromDockerImageAsset(new DockerImageAsset(stack, 'dockerImageAsset', { + directory: path.join(__dirname, 'batchjob-image'), + })), + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Batch::JobDefinition', { + ...pascalCaseExpectedProps, + ContainerProperties: { + ...pascalCaseExpectedProps.ContainerProperties, + Image: { + 'Fn::Sub': '${AWS::AccountId}.dkr.ecr.${AWS::Region}.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}:8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b', + }, + }, + }); + }); + + test('correctly renders images from repositories', () => { + // GIVEN + const repo = new ecr.Repository(stack, 'Repo'); + + // WHEN + new EcsJobDefinition(stack, 'ECSJobDefn', { + container: new ContainerDefinition(stack, 'EcsContainer', { + ...defaultContainerProps, + image: ecs.ContainerImage.fromEcrRepository(repo, 'my-tag'), + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Batch::JobDefinition', { + ...pascalCaseExpectedProps, + ContainerProperties: { + ...pascalCaseExpectedProps.ContainerProperties, + Image: { + 'Fn::Join': [ + '', + [ + { + 'Fn::Select': [ + 4, + { + 'Fn::Split': [ + ':', + { 'Fn::GetAtt': ['Repo02AC86CF', 'Arn'] }, + ], + }, + ], + }, + '.dkr.ecr.', + { + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { 'Fn::GetAtt': ['Repo02AC86CF', 'Arn'] }, + ], + }, + ], + }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { Ref: 'Repo02AC86CF' }, + ':my-tag', + ], + ], + }, + }, + }); + }); }); describe('EC2 containers', () => { diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B.assets.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B.assets.json index 0f5545b944f8a..337b93a040095 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B.assets.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B.assets.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/Dockerfile b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/Dockerfile new file mode 100644 index 0000000000000..235b30e9661ed --- /dev/null +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/Dockerfile @@ -0,0 +1,5 @@ +FROM public.ecr.aws/lambda/python:3.6 +EXPOSE 8000 +WORKDIR /src +ADD . /src +CMD python3 index.py diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/index.py b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/index.py new file mode 100644 index 0000000000000..337ed86e5f2ec --- /dev/null +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b/index.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +import os +import pprint + +print('Hello from Batch!') +pprint.pprint(dict(os.environ)) diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/cdk.out b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/cdk.out index b72fef144f05c..7925065efbcc4 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"30.1.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/integ.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/integ.json index 38e1bef264143..65cdb342d321b 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "testCases": { "BatchEcsJobDefinitionTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/manifest.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/manifest.json index 56806b0c43fa0..fc2ecf410a460 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "artifacts": { "stack.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c292a4e3a2a62cd3f3134971757eb866dc5224bc69f7109ec27d12ab882f2345.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9186f9ef6b963bbe6a32d639a67ffce49446d36bd04de52f495e7ee371e3ce3d.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -219,6 +219,24 @@ "data": "ECSFargateJobDefn327BE725" } ], + "/stack/EcsDockerContainer/ExecutionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsDockerContainerExecutionRole7AA53A24" + } + ], + "/stack/EcsDockerContainer/ExecutionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsDockerContainerExecutionRoleDefaultPolicyF58C2301" + } + ], + "/stack/ECSDockerJobDefn/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ECSDockerJobDefnF388CFCF" + } + ], "/stack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.assets.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.assets.json index 7f8e8b1897c40..627400ce950fd 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.assets.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.assets.json @@ -1,7 +1,7 @@ { - "version": "30.1.0", + "version": "31.0.0", "files": { - "c292a4e3a2a62cd3f3134971757eb866dc5224bc69f7109ec27d12ab882f2345": { + "9186f9ef6b963bbe6a32d639a67ffce49446d36bd04de52f495e7ee371e3ce3d": { "source": { "path": "stack.template.json", "packaging": "file" @@ -9,11 +9,24 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "c292a4e3a2a62cd3f3134971757eb866dc5224bc69f7109ec27d12ab882f2345.json", + "objectKey": "9186f9ef6b963bbe6a32d639a67ffce49446d36bd04de52f495e7ee371e3ce3d.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } } }, - "dockerImages": {} + "dockerImages": { + "8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b": { + "source": { + "directory": "asset.8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b" + }, + "destinations": { + "current_account-current_region": { + "repositoryName": "cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}", + "imageTag": "8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-image-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.template.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.template.json index 372ef4d21be9d..08c0c81ad985a 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.template.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/stack.template.json @@ -636,6 +636,109 @@ "AttemptDurationSeconds": 600 } } + }, + "EcsDockerContainerExecutionRole7AA53A24": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "EcsDockerContainerExecutionRoleDefaultPolicyF58C2301": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/", + { + "Fn::Sub": "cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsDockerContainerExecutionRoleDefaultPolicyF58C2301", + "Roles": [ + { + "Ref": "EcsDockerContainerExecutionRole7AA53A24" + } + ] + } + }, + "ECSDockerJobDefnF388CFCF": { + "Type": "AWS::Batch::JobDefinition", + "Properties": { + "Type": "container", + "ContainerProperties": { + "Environment": [], + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "EcsDockerContainerExecutionRole7AA53A24", + "Arn" + ] + }, + "Image": { + "Fn::Sub": "${AWS::AccountId}.dkr.ecr.${AWS::Region}.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}:8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b" + }, + "ReadonlyRootFilesystem": false, + "ResourceRequirements": [ + { + "Type": "MEMORY", + "Value": "32768" + }, + { + "Type": "VCPU", + "Value": "16" + } + ] + }, + "PlatformCapabilities": [ + "EC2" + ], + "RetryStrategy": {}, + "Timeout": {} + } } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/tree.json b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/tree.json index ad931926998b5..2bf240ea3f79b 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPC", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet1": { @@ -75,16 +75,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PublicSubnet1/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -192,14 +192,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet2": { @@ -242,16 +242,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PublicSubnet2/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -359,14 +359,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet1": { @@ -409,16 +409,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -478,14 +478,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet2": { @@ -528,16 +528,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PrivateSubnet2/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -597,14 +597,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "IGW": { @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnInternetGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "VPCGW": { @@ -641,14 +641,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPCGatewayAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.Vpc", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "myFileSystem": { @@ -671,8 +671,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-efs.CfnFileSystem", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EfsSecurityGroup": { @@ -705,14 +705,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EfsMountTarget1": { @@ -738,8 +738,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-efs.CfnMountTarget", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EfsMountTarget2": { @@ -765,14 +765,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-efs.CfnMountTarget", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-efs.FileSystem", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "myContainer": { @@ -787,8 +787,8 @@ "id": "ImportExecutionRole", "path": "stack/myContainer/ExecutionRole/ImportExecutionRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -812,20 +812,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.EcsEc2ContainerDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "ECSJobDefn": { @@ -910,14 +910,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.CfnJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.EcsJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "myFargateContainer": { @@ -932,8 +932,8 @@ "id": "ImportExecutionRole", "path": "stack/myFargateContainer/ExecutionRole/ImportExecutionRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -957,20 +957,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.EcsFargateContainerDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "ECSFargateJobDefn": { @@ -1045,36 +1045,237 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.CfnJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-batch.EcsJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "dockerImageAsset": { + "id": "dockerImageAsset", + "path": "stack/dockerImageAsset", + "children": { + "Staging": { + "id": "Staging", + "path": "stack/dockerImageAsset/Staging", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Repository": { + "id": "Repository", + "path": "stack/dockerImageAsset/Repository", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "EcsDockerContainer": { + "id": "EcsDockerContainer", + "path": "stack/EcsDockerContainer", + "children": { + "ExecutionRole": { + "id": "ExecutionRole", + "path": "stack/EcsDockerContainer/ExecutionRole", + "children": { + "ImportExecutionRole": { + "id": "ImportExecutionRole", + "path": "stack/EcsDockerContainer/ExecutionRole/ImportExecutionRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "stack/EcsDockerContainer/ExecutionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "stack/EcsDockerContainer/ExecutionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "stack/EcsDockerContainer/ExecutionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/", + { + "Fn::Sub": "cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "policyName": "EcsDockerContainerExecutionRoleDefaultPolicyF58C2301", + "roles": [ + { + "Ref": "EcsDockerContainerExecutionRole7AA53A24" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "ECSDockerJobDefn": { + "id": "ECSDockerJobDefn", + "path": "stack/ECSDockerJobDefn", + "children": { + "Resource": { + "id": "Resource", + "path": "stack/ECSDockerJobDefn/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Batch::JobDefinition", + "aws:cdk:cloudformation:props": { + "type": "container", + "containerProperties": { + "image": { + "Fn::Sub": "${AWS::AccountId}.dkr.ecr.${AWS::Region}.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-${AWS::AccountId}-${AWS::Region}:8b518243ecbfcfd08b4734069e7e74ff97b7889dfde0a60d16e7bdc96e6c593b" + }, + "environment": [], + "executionRoleArn": { + "Fn::GetAtt": [ + "EcsDockerContainerExecutionRole7AA53A24", + "Arn" + ] + }, + "readonlyRootFilesystem": false, + "resourceRequirements": [ + { + "type": "MEMORY", + "value": "32768" + }, + { + "type": "VCPU", + "value": "16" + } + ] + }, + "platformCapabilities": [ + "EC2" + ], + "retryStrategy": {}, + "timeout": {} + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "stack/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "stack/CheckBootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "BatchEcsJobDefinitionTest": { @@ -1090,7 +1291,7 @@ "path": "BatchEcsJobDefinitionTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.264" + "version": "10.1.270" } }, "DeployAssert": { @@ -1101,33 +1302,33 @@ "id": "BootstrapVersion", "path": "BatchEcsJobDefinitionTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "BatchEcsJobDefinitionTest/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTest", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", "version": "0.0.0" } }, @@ -1136,13 +1337,13 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.264" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.ts b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.ts index ad6e7d6887325..f35ddfbac8d33 100644 --- a/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.ts +++ b/packages/@aws-cdk/aws-batch-alpha/test/integ.ecs-job-definition.ts @@ -1,9 +1,12 @@ import { Vpc } from 'aws-cdk-lib/aws-ec2'; import { ContainerImage, FargatePlatformVersion } from 'aws-cdk-lib/aws-ecs'; import * as efs from 'aws-cdk-lib/aws-efs'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; import { App, Duration, Size, Stack } from 'aws-cdk-lib'; import * as integ from '@aws-cdk/integ-tests-alpha'; import * as batch from '../lib'; +import { DockerImageAsset } from 'aws-cdk-lib/aws-ecr-assets'; +import * as path from 'path'; const app = new App(); const stack = new Stack(app, 'stack'); @@ -66,6 +69,16 @@ new batch.EcsJobDefinition(stack, 'ECSFargateJobDefn', { timeout: Duration.minutes(10), }); +new batch.EcsJobDefinition(stack, 'ECSDockerJobDefn', { + container: new batch.EcsEc2ContainerDefinition(stack, 'EcsDockerContainer', { + cpu: 16, + memory: Size.mebibytes(32768), + image: ecs.ContainerImage.fromDockerImageAsset(new DockerImageAsset(stack, 'dockerImageAsset', { + directory: path.join(__dirname, 'batchjob-image'), + })), + }), +}); + new integ.IntegTest(app, 'BatchEcsJobDefinitionTest', { testCases: [stack], });