diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/README.md b/packages/@aws-cdk-containers/ecs-service-extensions/README.md index 115c8785ddbc1..84dd42fc93eff 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/README.md +++ b/packages/@aws-cdk-containers/ecs-service-extensions/README.md @@ -109,7 +109,43 @@ nameDescription.add(new Container({ Every `ServiceDescription` requires at minimum that you add a `Container` extension which defines the main application (essential) container to run for the service. -After that, you can optionally enable additional features for the service using the `ServiceDescription.add()` method: +### Logging using `awslogs` log driver + +If no observability extensions have been configured for a service, the ECS Service Extensions configures an `awslogs` log driver for the application container of the service to send the container logs to CloudWatch Logs. + +You can either provide a log group to the `Container` extension or one will be created for you by the CDK. + +Following is an example of an application with an `awslogs` log driver configured for the application container: + +```ts +const environment = new Environment(stack, 'production'); + +const nameDescription = new ServiceDescription(); +nameDescription.add(new Container({ + cpu: 1024, + memoryMiB: 2048, + trafficPort: 80, + image: ContainerImage.fromRegistry('nathanpeck/name'), + environment: { + PORT: '80', + }, + logGroup: new awslogs.LogGroup(stack, 'MyLogGroup'), +})); +``` + +If a log group is not provided, no observability extensions have been created, and the `ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER` feature flag is enabled, then logging will be configured by default and a log group will be created for you. + +The `ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER` feature flag is enabled by default in any CDK apps that are created with CDK v1.140.0 or v2.8.0 and later. + +To enable default logging for previous versions, ensure that the `ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER` flag within the application stack context is set to true, like so: + +```ts +stack.node.setContext(cxapi.ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER, true); +``` + +Alternatively, you can also set the feature flag in the `cdk.json` file. For more information, refer the [docs](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html). + +After adding the `Container` extension, you can optionally enable additional features for the service using the `ServiceDescription.add()` method: ```ts nameDescription.add(new AppMeshExtension({ mesh })); diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts index 10c61401e90d3..2711108e4f0ff 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts @@ -1,4 +1,7 @@ import * as ecs from '@aws-cdk/aws-ecs'; +import * as awslogs from '@aws-cdk/aws-logs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { Service } from '../service'; import { ServiceExtension } from './extension-interfaces'; @@ -38,6 +41,13 @@ export interface ContainerExtensionProps { readonly environment?: { [key: string]: string, } + + /** + * The log group into which application container logs should be routed. + * + * @default - A log group is automatically created for you if the `ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER` feature flag is set. + */ + readonly logGroup?: awslogs.ILogGroup; } /** @@ -51,6 +61,11 @@ export class Container extends ServiceExtension { */ public readonly trafficPort: number; + /** + * The log group into which application container logs should be routed. + */ + public logGroup?: awslogs.ILogGroup; + /** * The settings for the container. */ @@ -60,11 +75,12 @@ export class Container extends ServiceExtension { super('service-container'); this.props = props; this.trafficPort = props.trafficPort; + this.logGroup = props.logGroup; } - // @ts-ignore - Ignore unused params that are required for abstract class extend public prehook(service: Service, scope: Construct) { this.parentService = service; + this.scope = scope; } // This hook sets the overall task resource requirements to the @@ -93,6 +109,31 @@ export class Container extends ServiceExtension { containerProps = hookProvider.mutateContainerDefinition(containerProps); }); + // If no observability extensions have been added to the service description then we can configure the `awslogs` log driver + if (!containerProps.logging) { + // Create a log group for the service if one is not provided by the user (only if feature flag is set) + if (!this.logGroup && this.parentService.node.tryGetContext(cxapi.ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER)) { + this.logGroup = new awslogs.LogGroup(this.scope, `${this.parentService.id}-logs`, { + logGroupName: `${this.parentService.id}-logs`, + removalPolicy: cdk.RemovalPolicy.DESTROY, + retention: awslogs.RetentionDays.ONE_MONTH, + }); + } + + if (this.logGroup) { + containerProps = { + ...containerProps, + logging: new ecs.AwsLogDriver({ + streamPrefix: this.parentService.id, + logGroup: this.logGroup, + }), + }; + } + } else { + if (this.logGroup) { + throw Error(`Log configuration already specified. You cannot provide a log group for the application container of service '${this.parentService.id}' while also adding log configuration separately using service extensions.`); + } + } this.container = taskDefinition.addContainer('app', containerProps); // Create a port mapping for the container diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts index 7909d5b32053f..c90c59edaea31 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts @@ -54,6 +54,8 @@ export interface ServiceProps { /** * The options for configuring the auto scaling target. + * + * @default none */ readonly autoScaleTaskCount?: AutoScalingOptions; } @@ -196,7 +198,6 @@ export class Service extends Construct { // Ensure that the task definition supports both EC2 and Fargate compatibility: ecs.Compatibility.EC2_AND_FARGATE, } as ecs.TaskDefinitionProps; - for (const extensions in this.serviceDescription.extensions) { if (this.serviceDescription.extensions[extensions]) { taskDefProps = this.serviceDescription.extensions[extensions].modifyTaskDefinitionProps(taskDefProps); diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 6fad145eafd8c..e59612c4d6b3d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -70,6 +70,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69" }, @@ -98,6 +99,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/appmesh.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/appmesh.test.ts index c6fbd24d9858f..0d54e8e43570f 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/appmesh.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/appmesh.test.ts @@ -33,7 +33,6 @@ describe('appmesh', () => { }); // THEN - // Ensure that task has an App Mesh sidecar expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/cloudwatch-agent.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/cloudwatch-agent.test.ts index 08cd8dfbe8a04..d9ff4f3b50fae 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/cloudwatch-agent.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/cloudwatch-agent.test.ts @@ -27,7 +27,6 @@ describe('cloudwatch agent', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/container.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/container.test.ts new file mode 100644 index 0000000000000..3e9b2e79dd9e8 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/container.test.ts @@ -0,0 +1,316 @@ +import '@aws-cdk/assert-internal/jest'; +import * as autoscaling from '@aws-cdk/aws-autoscaling'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as iam from '@aws-cdk/aws-iam'; +import * as awslogs from '@aws-cdk/aws-logs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import { Container, Environment, EnvironmentCapacityType, FireLensExtension, Service, ServiceDescription } from '../lib'; + +describe('container', () => { + test('should be able to add a container to the service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addAsgCapacityProvider(new ecs.AsgCapacityProvider(stack, 'Provider', { + autoScalingGroup: new autoscaling.AutoScalingGroup(stack, 'DefaultAutoScalingGroup', { + vpc, + machineImage: ec2.MachineImage.latestAmazonLinux(), + instanceType: new ec2.InstanceType('t2.micro'), + }), + })); + + const environment = new Environment(stack, 'production', { + vpc, + cluster, + capacityType: EnvironmentCapacityType.EC2, + }); + const serviceDescription = new ServiceDescription(); + const taskRole = new iam.Role(stack, 'CustomTaskRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + taskRole, + }); + + // THEN + expect(stack).toCountResources('AWS::ECS::Service', 1); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Essential: true, + Image: 'nathanpeck/name', + Memory: 512, + Name: 'app', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + Ulimits: [ + { + HardLimit: 1024000, + Name: 'nofile', + SoftLimit: 1024000, + }, + ], + }, + ], + Cpu: '256', + Family: 'myservicetaskdefinition', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'EC2', + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'CustomTaskRole3C6B13FD', + 'Arn', + ], + }, + }); + + + }); + + test('should be able to enable default logging behavior - with enable default log driver feature flag', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addAsgCapacityProvider(new ecs.AsgCapacityProvider(stack, 'Provider', { + autoScalingGroup: new autoscaling.AutoScalingGroup(stack, 'DefaultAutoScalingGroup', { + vpc, + machineImage: ec2.MachineImage.latestAmazonLinux(), + instanceType: new ec2.InstanceType('t2.micro'), + }), + })); + + const environment = new Environment(stack, 'production', { + vpc, + cluster, + capacityType: EnvironmentCapacityType.EC2, + }); + const serviceDescription = new ServiceDescription(); + const taskRole = new iam.Role(stack, 'CustomTaskRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + taskRole, + }); + + // THEN + expect(stack).toCountResources('AWS::ECS::Service', 1); + + // Ensure that the log group was created + expect(stack).toHaveResource('AWS::Logs::LogGroup'); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Essential: true, + Image: 'nathanpeck/name', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'myservicelogs176EE19F', + }, + 'awslogs-stream-prefix': 'my-service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'app', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + Ulimits: [ + { + HardLimit: 1024000, + Name: 'nofile', + SoftLimit: 1024000, + }, + ], + }, + ], + Cpu: '256', + Family: 'myservicetaskdefinition', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'EC2', + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'CustomTaskRole3C6B13FD', + 'Arn', + ], + }, + }); + + + }); + + test('should be able to add user-provided log group in the log driver options', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addAsgCapacityProvider(new ecs.AsgCapacityProvider(stack, 'Provider', { + autoScalingGroup: new autoscaling.AutoScalingGroup(stack, 'DefaultAutoScalingGroup', { + vpc, + machineImage: ec2.MachineImage.latestAmazonLinux(), + instanceType: new ec2.InstanceType('t2.micro'), + }), + })); + + const environment = new Environment(stack, 'production', { + vpc, + cluster, + capacityType: EnvironmentCapacityType.EC2, + }); + const serviceDescription = new ServiceDescription(); + const taskRole = new iam.Role(stack, 'CustomTaskRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + logGroup: new awslogs.LogGroup(stack, 'MyLogGroup'), + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + taskRole, + }); + + // THEN + expect(stack).toCountResources('AWS::ECS::Service', 1); + + // Ensure that the log group was created + expect(stack).toHaveResource('AWS::Logs::LogGroup'); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Essential: true, + Image: 'nathanpeck/name', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'MyLogGroup5C0DAD85', + }, + 'awslogs-stream-prefix': 'my-service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'app', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + Ulimits: [ + { + HardLimit: 1024000, + Name: 'nofile', + SoftLimit: 1024000, + }, + ], + }, + ], + Cpu: '256', + Family: 'myservicetaskdefinition', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'EC2', + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'CustomTaskRole3C6B13FD', + 'Arn', + ], + }, + }); + + + }); + + test('should error when log group is provided in the container extension and another observability extension is added', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + logGroup: new awslogs.LogGroup(stack, 'MyLogGroup'), + })); + serviceDescription.add(new FireLensExtension()); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + }); + }).toThrow(/Log configuration already specified. You cannot provide a log group for the application container of service 'my-service' while also adding log configuration separately using service extensions./); + }); + +}); diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index faee3f71397ab..556524b695267 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -291,6 +291,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "namelogsF4B17D31" + }, + "awslogs-stream-prefix": "name", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 512, "Name": "app", "PortMappings": [ @@ -309,6 +321,12 @@ } ], "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "nametaskdefinitionExecutionRole45AC5C9A", + "Arn" + ] + }, "Family": "awsecsintegnametaskdefinition0EA6A1A0", "Memory": "512", "NetworkMode": "awsvpc", @@ -329,6 +347,71 @@ "nameserviceTaskRecordManagerRuleStopped66D08B70" ] }, + "nametaskdefinitionExecutionRole45AC5C9A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "nameserviceTaskRecordManagerCleanupE19F1043", + "nameserviceTaskRecordManagerRuleRunningCD85F46F", + "nameserviceTaskRecordManagerRuleStopped66D08B70" + ] + }, + "nametaskdefinitionExecutionRoleDefaultPolicyF7942D20": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "namelogsF4B17D31", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "nametaskdefinitionExecutionRoleDefaultPolicyF7942D20", + "Roles": [ + { + "Ref": "nametaskdefinitionExecutionRole45AC5C9A" + } + ] + }, + "DependsOn": [ + "nameserviceTaskRecordManagerCleanupE19F1043", + "nameserviceTaskRecordManagerRuleRunningCD85F46F", + "nameserviceTaskRecordManagerRuleStopped66D08B70" + ] + }, + "namelogsF4B17D31": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "name-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "nameserviceService8015C8D6": { "Type": "AWS::ECS::Service", "Properties": { @@ -714,7 +797,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3Bucket1E7F92B6" }, "S3Key": { "Fn::Join": [ @@ -727,7 +810,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3VersionKey86FCA825" } ] } @@ -740,7 +823,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3VersionKey86FCA825" } ] } @@ -877,7 +960,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3Bucket1E7F92B6" }, "S3Key": { "Fn::Join": [ @@ -890,7 +973,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3VersionKey86FCA825" } ] } @@ -903,7 +986,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" + "Ref": "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3VersionKey86FCA825" } ] } @@ -1190,7 +1273,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16" }, "S3Key": { "Fn::Join": [ @@ -1203,7 +1286,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -1216,7 +1299,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + "Ref": "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B" } ] } @@ -1242,17 +1325,17 @@ } }, "Parameters": { - "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD": { + "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3Bucket1E7F92B6": { "Type": "String", - "Description": "S3 bucket for asset \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" + "Description": "S3 bucket for asset \"8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725d\"" }, - "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F": { + "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dS3VersionKey86FCA825": { "Type": "String", - "Description": "S3 key for asset version \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" + "Description": "S3 key for asset version \"8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725d\"" }, - "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eArtifactHashC1CF90D5": { + "AssetParameters8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725dArtifactHash0F81F2AB": { "Type": "String", - "Description": "Artifact hash for asset \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" + "Description": "Artifact hash for asset \"8f06a3db22794ebc7ff89b4745fd706afd46e17816fe46da72e5125cabae725d\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1266,17 +1349,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3Bucket36F31A16": { "Type": "String", - "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 bucket for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87S3VersionKeyF80D542B": { "Type": "String", - "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "S3 key for asset version \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" }, - "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "AssetParameters3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87ArtifactHash40DDF5EE": { "Type": "String", - "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + "Description": "Artifact hash for asset \"3744fa896361f81b76b1efde632ac07b1920ce09a4ca1ff15ab486f262a19b87\"" } }, "Outputs": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json index 5fbaf177162df..af4f8829a1501 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json @@ -548,6 +548,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "namelogsF4B17D31" + }, + "awslogs-stream-prefix": "name", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 2048, "Name": "app", "PortMappings": [ @@ -566,6 +578,12 @@ } ], "Cpu": "1024", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "nametaskdefinitionExecutionRole45AC5C9A", + "Arn" + ] + }, "Family": "awsecsintegnametaskdefinition0EA6A1A0", "Memory": "2048", "NetworkMode": "awsvpc", @@ -581,6 +599,61 @@ } } }, + "nametaskdefinitionExecutionRole45AC5C9A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "nametaskdefinitionExecutionRoleDefaultPolicyF7942D20": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "namelogsF4B17D31", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "nametaskdefinitionExecutionRoleDefaultPolicyF7942D20", + "Roles": [ + { + "Ref": "nametaskdefinitionExecutionRole45AC5C9A" + } + ] + } + }, + "namelogsF4B17D31": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "name-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "nameserviceService8015C8D6": { "Type": "AWS::ECS::Service", "Properties": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json index c85f5d9b0231d..48775db8f3c84 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json @@ -209,6 +209,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "Servicelogs9F4E1F70" + }, + "awslogs-stream-prefix": "Service", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 512, "Name": "app", "PortMappings": [ @@ -227,6 +239,12 @@ } ], "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "ServicetaskdefinitionExecutionRoleD09F4578", + "Arn" + ] + }, "Family": "importedenvironmentintegServicetaskdefinition63936B87", "Memory": "512", "NetworkMode": "awsvpc", @@ -242,6 +260,61 @@ } } }, + "ServicetaskdefinitionExecutionRoleD09F4578": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ServicetaskdefinitionExecutionRoleDefaultPolicy25CEAFC5": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Servicelogs9F4E1F70", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ServicetaskdefinitionExecutionRoleDefaultPolicy25CEAFC5", + "Roles": [ + { + "Ref": "ServicetaskdefinitionExecutionRoleD09F4578" + } + ] + } + }, + "Servicelogs9F4E1F70": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "Service-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "ServiceserviceService6A153CB8": { "Type": "AWS::ECS::Service", "Properties": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json index 91ce21c4a2c5f..fa97c69cefc1c 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json @@ -1103,6 +1103,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "nameproductionlogsD0BFFE8C" + }, + "awslogs-stream-prefix": "name-production", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 2048, "Name": "app", "PortMappings": [ @@ -1266,11 +1278,6 @@ } } }, - "nameproductiontaskdefinitionenvoyLogGroupF79A2732": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "nameproductiontaskdefinitionExecutionRoleB72DD86B": { "Type": "AWS::IAM::Role", "Properties": { @@ -1293,6 +1300,19 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "nameproductionlogsD0BFFE8C", + "Arn" + ] + } + }, { "Action": [ "ecr:BatchCheckLayerAvailability", @@ -1356,6 +1376,20 @@ ] } }, + "nameproductiontaskdefinitionenvoyLogGroupF79A2732": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "nameproductionlogsD0BFFE8C": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "name-production-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "nameproductionenvoytoappmesh1B44B04A": { "Type": "AWS::IAM::Policy", "Properties": { @@ -1631,6 +1665,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "namedevelopmentlogs108670CC" + }, + "awslogs-stream-prefix": "name-development", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 2048, "Name": "app", "PortMappings": [ @@ -1794,11 +1840,6 @@ } } }, - "namedevelopmenttaskdefinitionenvoyLogGroupF8FCAFD6": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "namedevelopmenttaskdefinitionExecutionRole48B53E4E": { "Type": "AWS::IAM::Role", "Properties": { @@ -1821,6 +1862,19 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "namedevelopmentlogs108670CC", + "Arn" + ] + } + }, { "Action": [ "ecr:BatchCheckLayerAvailability", @@ -1884,6 +1938,20 @@ ] } }, + "namedevelopmenttaskdefinitionenvoyLogGroupF8FCAFD6": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "namedevelopmentlogs108670CC": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "name-development-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "namedevelopmentenvoytoappmesh45FF08AA": { "Type": "AWS::IAM::Policy", "Properties": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json index 465a7ce4b3374..24cd1d0a4e434 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json @@ -596,6 +596,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "PublisherlogsDF0C1067" + }, + "awslogs-stream-prefix": "Publisher", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 512, "Name": "app", "PortMappings": [ @@ -614,6 +626,12 @@ } ], "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "PublishertaskdefinitionExecutionRole5C00C542", + "Arn" + ] + }, "Family": "awsecsintegPublishertaskdefinitionD50610D0", "Memory": "512", "NetworkMode": "awsvpc", @@ -629,6 +647,61 @@ } } }, + "PublishertaskdefinitionExecutionRole5C00C542": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PublishertaskdefinitionExecutionRoleDefaultPolicy681FD8E6": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PublisherlogsDF0C1067", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PublishertaskdefinitionExecutionRoleDefaultPolicy681FD8E6", + "Roles": [ + { + "Ref": "PublishertaskdefinitionExecutionRole5C00C542" + } + ] + } + }, + "PublisherlogsDF0C1067": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "Publisher-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "PublisherserviceService9EB00F60": { "Type": "AWS::ECS::Service", "Properties": { @@ -901,6 +974,18 @@ ], "Essential": true, "Image": "nathanpeck/name", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "Workerlogs2994AC4D" + }, + "awslogs-stream-prefix": "Worker", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, "Memory": 512, "Name": "app", "PortMappings": [ @@ -919,6 +1004,12 @@ } ], "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "WorkertaskdefinitionExecutionRole3C1A1848", + "Arn" + ] + }, "Family": "awsecsintegWorkertaskdefinition32B60762", "Memory": "512", "NetworkMode": "awsvpc", @@ -934,6 +1025,61 @@ } } }, + "WorkertaskdefinitionExecutionRole3C1A1848": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "WorkertaskdefinitionExecutionRoleDefaultPolicy6E199B19": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Workerlogs2994AC4D", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "WorkertaskdefinitionExecutionRoleDefaultPolicy6E199B19", + "Roles": [ + { + "Ref": "WorkertaskdefinitionExecutionRole3C1A1848" + } + ] + } + }, + "Workerlogs2994AC4D": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "Worker-logs", + "RetentionInDays": 30 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "WorkerserviceService68C5A5C3": { "Type": "AWS::ECS::Service", "Properties": { @@ -1184,7 +1330,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3Bucket151170D5" + "Ref": "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91S3Bucket1FFDEA8D" }, "S3Key": { "Fn::Join": [ @@ -1197,7 +1343,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D" + "Ref": "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91S3VersionKeyA60C027B" } ] } @@ -1210,7 +1356,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D" + "Ref": "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91S3VersionKeyA60C027B" } ] } @@ -1326,17 +1472,17 @@ } }, "Parameters": { - "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3Bucket151170D5": { + "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91S3Bucket1FFDEA8D": { "Type": "String", - "Description": "S3 bucket for asset \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" + "Description": "S3 bucket for asset \"a820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91\"" }, - "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D": { + "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91S3VersionKeyA60C027B": { "Type": "String", - "Description": "S3 key for asset version \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" + "Description": "S3 key for asset version \"a820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91\"" }, - "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dArtifactHash167B1C30": { + "AssetParametersa820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91ArtifactHashC1953821": { "Type": "String", - "Description": "Artifact hash for asset \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" + "Description": "Artifact hash for asset \"a820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts index 39d26ef371f17..8db284b856e28 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts @@ -1,11 +1,8 @@ import { ABSENT } from '@aws-cdk/assert-internal'; import '@aws-cdk/assert-internal/jest'; -import * as autoscaling from '@aws-cdk/aws-autoscaling'; -import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; -import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Container, EnvironmentCapacityType, Environment, Service, ServiceDescription } from '../lib'; +import { Container, Environment, Service, ServiceDescription } from '../lib'; describe('service', () => { test('should error if a service is prepared with no addons', () => { @@ -25,87 +22,6 @@ describe('service', () => { }).toThrow(/Service 'my-service' must have a Container extension/); - }); - - test('should be able to add a container to the service', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addAsgCapacityProvider(new ecs.AsgCapacityProvider(stack, 'Provider', { - autoScalingGroup: new autoscaling.AutoScalingGroup(stack, 'DefaultAutoScalingGroup', { - vpc, - machineImage: ec2.MachineImage.latestAmazonLinux(), - instanceType: new ec2.InstanceType('t2.micro'), - }), - })); - - const environment = new Environment(stack, 'production', { - vpc, - cluster, - capacityType: EnvironmentCapacityType.EC2, - }); - const serviceDescription = new ServiceDescription(); - const taskRole = new iam.Role(stack, 'CustomTaskRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - - serviceDescription.add(new Container({ - cpu: 256, - memoryMiB: 512, - trafficPort: 80, - image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), - })); - - new Service(stack, 'my-service', { - environment, - serviceDescription, - taskRole, - }); - - // THEN - expect(stack).toCountResources('AWS::ECS::Service', 1); - - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 256, - Essential: true, - Image: 'nathanpeck/name', - Memory: 512, - Name: 'app', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - Ulimits: [ - { - HardLimit: 1024000, - Name: 'nofile', - SoftLimit: 1024000, - }, - ], - }, - ], - Cpu: '256', - Family: 'myservicetaskdefinition', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'EC2', - 'FARGATE', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'CustomTaskRole3C6B13FD', - 'Arn', - ], - }, - }); - - }); test('allows scaling on a target CPU utilization', () => { diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 74f4ff63082a6..71ed4856ec85a 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -170,6 +170,14 @@ export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cl */ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; +/** + * Enable this feature flag to configure default logging behavior for the ECS Service Extensions. This will enable the + * `awslogs` log driver for the application container of the service to send the container logs to CloudWatch Logs. + * + * This is a feature flag as the new behavior provides a better default experience for the users. + */ +export const ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER = '@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver'; + /** * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default @@ -197,6 +205,7 @@ export const FUTURE_FLAGS: { [key: string]: boolean } = { [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, + [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: true, // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', @@ -235,6 +244,7 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [EFS_DEFAULT_ENCRYPTION_AT_REST]: false, [LAMBDA_RECOGNIZE_VERSION_PROPS]: false, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: false, + [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: false, }; export function futureFlagDefault(flag: string): boolean | undefined {