diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts index be15cf6c195c5..c079f1aae02a3 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts @@ -374,6 +374,15 @@ export class TaskDefinition extends TaskDefinitionBase { */ public readonly ephemeralStorageGiB?: number; + /** + * The process namespace to use for the containers in the task. + * + * Only supported for tasks that are hosted on AWS Fargate if the tasks + * are using platform version 1.4.0 or later (Linux). + * Not supported in Windows containers. + */ + public readonly pidMode?: PidMode; + /** * The container definitions. */ @@ -455,6 +464,7 @@ export class TaskDefinition extends TaskDefinitionBase { } this.ephemeralStorageGiB = props.ephemeralStorageGiB; + this.pidMode = props.pidMode; // validate the cpu and memory size for the Windows operation system family. if (props.runtimePlatform?.operatingSystemFamily?.isWindows()) { @@ -487,7 +497,7 @@ export class TaskDefinition extends TaskDefinitionBase { cpu: props.cpu, memory: props.memoryMiB, ipcMode: props.ipcMode, - pidMode: props.pidMode, + pidMode: this.pidMode, inferenceAccelerators: Lazy.any({ produce: () => !isFargateCompatible(this.compatibility) ? this.renderInferenceAccelerators() : undefined, diff --git a/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-service.ts index fa4194fa4f1aa..b4d1324e18947 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-service.ts @@ -128,6 +128,23 @@ export class FargateService extends BaseService implements IFargateService { throw new Error('Only one of SecurityGroup or SecurityGroups can be populated.'); } + // Platform versions not supporting referencesSecretJsonField, ephemeralStorageGiB, or pidMode on a task definition + const unsupportedPlatformVersions = [ + FargatePlatformVersion.VERSION1_0, + FargatePlatformVersion.VERSION1_1, + FargatePlatformVersion.VERSION1_2, + FargatePlatformVersion.VERSION1_3, + ]; + const isUnsupportedPlatformVersion = props.platformVersion && unsupportedPlatformVersions.includes(props.platformVersion); + + if (props.taskDefinition.ephemeralStorageGiB && isUnsupportedPlatformVersion) { + throw new Error(`The ephemeralStorageGiB feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later, got ${props.platformVersion}.`); + } + + if (props.taskDefinition.pidMode && isUnsupportedPlatformVersion) { + throw new Error(`The pidMode feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later, got ${props.platformVersion}.`); + } + super(scope, id, { ...props, desiredCount: props.desiredCount, @@ -153,9 +170,7 @@ export class FargateService extends BaseService implements IFargateService { } this.node.addValidation({ - validate: () => this.taskDefinition.referencesSecretJsonField - && props.platformVersion - && SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS.includes(props.platformVersion) + validate: () => this.taskDefinition.referencesSecretJsonField && isUnsupportedPlatformVersion ? [`The task definition of this service uses at least one container that references a secret JSON field. This feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later.`] : [], }); @@ -214,10 +229,3 @@ export enum FargatePlatformVersion { */ VERSION1_0 = '1.0.0', } - -const SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS = [ - FargatePlatformVersion.VERSION1_0, - FargatePlatformVersion.VERSION1_1, - FargatePlatformVersion.VERSION1_2, - FargatePlatformVersion.VERSION1_3, -]; diff --git a/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-service.test.ts b/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-service.test.ts index 3ef83abd316b3..0ecd027501019 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-service.test.ts @@ -1,6 +1,7 @@ import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { Annotations, Match, Template } from '../../../assertions'; import * as appscaling from '../../../aws-applicationautoscaling'; +import * as batch from '../../../aws-batch'; import * as cloudwatch from '../../../aws-cloudwatch'; import * as ec2 from '../../../aws-ec2'; import * as elbv2 from '../../../aws-elasticloadbalancingv2'; @@ -685,6 +686,92 @@ describe('fargate service', () => { }).toThrow(/one essential container/); }); + test('errors when platform version does not support containers which references secret JSON field', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', { + runtimePlatform: { + operatingSystemFamily: ecs.OperatingSystemFamily.LINUX, + cpuArchitecture: ecs.CpuArchitecture.ARM64, + }, + memoryLimitMiB: 512, + cpu: 256, + }); + + // Errors on validation, not on construction. + new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + platformVersion: ecs.FargatePlatformVersion.VERSION1_2, + }); + + taskDefinition.addContainer('main', { + image: ecs.ContainerImage.fromRegistry('somecontainer'), + secrets: { + envName: batch.Secret.fromSecretsManager(new secretsmanager.Secret(stack, 'testSecret'), 'secretField'), + }, + }); + + // THEN + expect(() => { + Template.fromStack(stack); + }).toThrow(/This feature requires platform version/); + }); + + test('errors when platform version does not support ephemeralStorageGiB', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', { + runtimePlatform: { + operatingSystemFamily: ecs.OperatingSystemFamily.LINUX, + cpuArchitecture: ecs.CpuArchitecture.ARM64, + }, + memoryLimitMiB: 512, + cpu: 256, + ephemeralStorageGiB: 100, + }); + + // WHEN + // THEN + expect(() => { + new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + platformVersion: ecs.FargatePlatformVersion.VERSION1_2, + }); + }).toThrow(/The ephemeralStorageGiB feature requires platform version/); + }); + + test('errors when platform version does not support pidMode', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', { + runtimePlatform: { + operatingSystemFamily: ecs.OperatingSystemFamily.LINUX, + cpuArchitecture: ecs.CpuArchitecture.ARM64, + }, + memoryLimitMiB: 512, + cpu: 256, + pidMode: ecs.PidMode.HOST, + }); + + // WHEN + // THEN + expect(() => { + new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + platformVersion: ecs.FargatePlatformVersion.VERSION1_2, + }); + }).toThrow(/The pidMode feature requires platform version/); + }); + test('allows adding the default container after creating the service', () => { // GIVEN const stack = new cdk.Stack();