From 96ec6139e1ad7637466e95b71e824965b081154f Mon Sep 17 00:00:00 2001 From: Madeline Kusters <80541297+madeline-k@users.noreply.github.com> Date: Sun, 27 Nov 2022 11:49:51 -0800 Subject: [PATCH 1/3] feat(ecs): enable Amazon ECS Service Connect --- packages/@aws-cdk/aws-ecs/README.md | 76 ++ .../@aws-cdk/aws-ecs/lib/base/base-service.ts | 222 ++++ .../aws-ecs/lib/base/task-definition.ts | 33 + packages/@aws-cdk/aws-ecs/lib/cluster.ts | 25 +- .../aws-ecs/lib/container-definition.ts | 87 +- .../aws-ecs/lib/log-drivers/aws-log-driver.ts | 1 + .../@aws-cdk/aws-ecs/test/cluster.test.ts | 18 + .../aws-ecs/test/container-definition.test.ts | 108 ++ .../test/fargate/fargate-service.test.ts | 416 +++++- ...efaultTestDeployAssert88F6A66F.assets.json | 19 + ...aultTestDeployAssert88F6A66F.template.json | 36 + .../aws-ecs-service-connect.assets.json | 19 + .../aws-ecs-service-connect.template.json | 659 ++++++++++ .../integ.service-connect.js.snapshot/cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 306 +++++ .../tree.json | 1128 +++++++++++++++++ .../test/fargate/integ.service-connect.ts | 63 + .../aws-ecs/test/task-definition.test.ts | 30 + .../000_cfn/000_official/000_AWS_ECS.json | 156 ++- 20 files changed, 3407 insertions(+), 8 deletions(-) create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.assets.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.template.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.assets.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.template.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.ts diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index de9cdb4493892..afbbd0dec4906 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -1233,3 +1233,79 @@ const cluster = new ecs.Cluster(this, 'Cluster', { }, }); ``` + +## Amazon ECS Service Connect + +Service Connect is a managed AWS mesh network offering. It simplifies DNS queries and inter-service communication for +ECS Services by allowing customers to set up simple DNS aliases for their services, which are accessible to all +services that have enabled Service Connect. + +To enable Service Connect, you must have created a CloudMap namespace. The CDK can infer your cluster's default CloudMap namespace, +or you can specify a custom namespace. You must also have created a named port mapping on at least one container in your Task Definition. + +```ts +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +declare const container: ecs.ContainerDefinition; + +container.addPortMappings({ + name: 'api', + containerPort: 8080, +}); + +taskDefinition.addContainer(container); + +cluster.addDefaultCloudMapNamespace({ + name: 'local', +}); + +const service = new ecs.FargateService(this, 'Service', { + cluster, + taskDefinition, + serviceConnectConfiguration: { + services: [ + { + portMappingName: 'api', + dnsName: 'http-api', + port: 80, + }, + ], + }, +}); +``` + +Service Connect-enabled services may now reach this service at `http-api:80`. Traffic to this endpoint will +be routed to the container's port 8080. + +To opt a service into using service connect without advertising a port, simply call the 'enableServiceConnect' method on an initialized service. + +```ts +const service = new ecs.FargateService(this, 'Service', { + cluster, + taskDefinition +) +service.enableServiceConnect(); +``` + +Service Connect also allows custom logging, Service Discovery name, and configuration of the port where service connect traffic is received. + +```ts +const customService = new ecs.FargateService(this, 'CustomizedService', { + cluster, + taskDefinition, + serviceConnectConfiguration: { + logDriver: ecs.LogDrivers.awslogs({ + streamPrefix: 'sc-traffic', + }), + services: [ + { + portMappingName: 'api', + dnsName: 'customized-api', + port: 80, + ingressPortOverride: 20040, + discoveryName: 'custom', + }, + ], + }, +}); +``` diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index e7a2b58d8855c..1e07fd1d4a0ab 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -23,6 +23,7 @@ import { LoadBalancerTargetOptions, NetworkMode, TaskDefinition } from '../base/ import { ICluster, CapacityProviderStrategy, ExecuteCommandLogging, Cluster } from '../cluster'; import { ContainerDefinition, Protocol } from '../container-definition'; import { CfnService } from '../ecs.generated'; +import { LogDriver, LogDriverConfig } from '../log-drivers/log-driver'; import { ScalableTaskCount } from './scalable-task-count'; /** @@ -104,6 +105,76 @@ export interface EcsTarget { export interface IEcsLoadBalancerTarget extends elbv2.IApplicationLoadBalancerTarget, elbv2.INetworkLoadBalancerTarget, elb.ILoadBalancerTarget { } +/** + * Interface for Service Connect configuration. + */ +export interface ServiceConnectProps { + /** + * The cloudmap namespace to register this service into. + * + * @default the cloudmap namespace specified on the cluster. + */ + readonly namespace?: string; + + /** + * The list of Services, including a port mapping, terse client alias, and optional intermediate DNS name. + * + * This property may be left blank if the current ECS service does not need to advertise any ports via Service Connect. + * + * @default none + */ + readonly services?: ServiceConnectService[]; + + /** + * The log driver configuration to use for the Service Connect agent logs. + * + * @default - none + */ + readonly logDriver?: LogDriver; +} + +/** + * Interface for service connect Service props. + */ +export interface ServiceConnectService { + /** + * portMappingName specifies which port and protocol combination should be used for this + * service connect service. + */ + readonly portMappingName: string; + + /** + * Optionally specifies an intermediate dns name to register in the CloudMap namespace. + * This is required if you wish to use the same port mapping name in more than one service. + * + * @default - port mapping name + */ + readonly discoveryName?: string; + + /** + * The terse DNS alias to use for this port mapping in the service connect mesh. + * Service Connect-enabled clients will be able to reach this service at + * http://dnsName:port. + * + * @default - No alias is created. The service is reachable at `portMappingName.namespace:port`. + */ + readonly dnsName?: string; + + /** + The port for clients to use to communicate with this service via Service Connect. + * + * @default the container port specified by the port mapping in portMappingName. + */ + readonly port?: number; + + /** + * Optional. The port on the Service Connect agent container to use for traffic ingress to this service. + * + * @default - none + */ + readonly ingressPortOverride?: number; +} + /** * The properties for the base Ec2Service or FargateService service. */ @@ -216,6 +287,14 @@ export interface BaseServiceOptions { * @default - undefined */ readonly enableExecuteCommand?: boolean; + + /** + * Configuration for Service Connect. + * + * @default No ports are advertised via Service Connect on this service, and the service + * cannot make requests to other services via Service Connect. + */ + readonly serviceConnectConfiguration?: ServiceConnectProps; } /** @@ -367,6 +446,9 @@ export abstract class BaseService extends Resource }); } + private static MIN_PORT = 1; + private static MAX_PORT = 65535; + /** * The security groups which manage the allowed network traffic for the service. */ @@ -417,6 +499,12 @@ export abstract class BaseService extends Resource */ protected serviceRegistries = new Array(); + /** + * The service connect configuration for this service. + * @internal + */ + protected _serviceConnectConfig?: CfnService.ServiceConnectConfigurationProperty; + private readonly resource: CfnService; private scalableTaskCount?: ScalableTaskCount; @@ -469,6 +557,7 @@ export abstract class BaseService extends Resource /* role: never specified, supplanted by Service Linked Role */ networkConfiguration: Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }), serviceRegistries: Lazy.any({ produce: () => this.serviceRegistries }, { omitEmptyArray: true }), + serviceConnectConfiguration: Lazy.any({ produce: () => this._serviceConnectConfig }, { omitEmptyArray: true }), ...additionalProps, }); @@ -502,6 +591,10 @@ export abstract class BaseService extends Resource this.enableCloudMap(props.cloudMapOptions); } + if (props.serviceConnectConfiguration) { + this.enableServiceConnect(props.serviceConnectConfiguration); + } + if (props.enableExecuteCommand) { this.enableExecuteCommand(); @@ -517,6 +610,135 @@ export abstract class BaseService extends Resource this.node.defaultChild = this.resource; } + /** * Enable Service Connect + */ + public enableServiceConnect(config?: ServiceConnectProps) { + if (this._serviceConnectConfig) { + throw new Error('Service connect configuration cannot be specified more than once.'); + } + + this.validateServiceConnectConfiguration(config); + + let cfg = config || {}; + + /** + * Namespace already exists as validated in validateServiceConnectConfiguration. + * Resolve which namespace to use by picking: + * 1. The namespace defined in service connect config. + * 2. The namespace defined in the cluster's defaultCloudMapNamespace property. + */ + let namespace; + if (this.cluster.defaultCloudMapNamespace) { + namespace = this.cluster.defaultCloudMapNamespace.namespaceName; + } + + if (cfg.namespace) { + namespace = cfg.namespace; + } + + /** + * Map services to CFN property types. This block manages: + * 1. Finding the correct port. + * 2. Client alias enumeration + */ + const services = cfg.services?.map(svc => { + const containerPort = this.taskDefinition.findPortMappingByName(svc.portMappingName)?.containerPort; + if (!containerPort) { + throw new Error(`Port mapping with name ${svc.portMappingName} does not exist.`); + } + const alias = { + port: svc.port || containerPort, + dnsName: svc.dnsName, + }; + + return { + portName: svc.portMappingName, + discoveryName: svc.discoveryName, + ingressPortOverride: svc.ingressPortOverride, + clientAliases: [alias], + } as CfnService.ServiceConnectServiceProperty; + }); + + let logConfig: LogDriverConfig | undefined; + if (cfg.logDriver && this.taskDefinition.defaultContainer) { + // Default container existence is validated in validateServiceConnectConfiguration. + // We only need the default container so that bind() can get the task definition from the container definition. + logConfig = cfg.logDriver.bind(this, this.taskDefinition.defaultContainer); + } + + this._serviceConnectConfig = { + enabled: true, + logConfiguration: logConfig, + namespace: namespace, + services: services, + }; + }; + + /** + * Validate Service Connect Configuration + */ + private validateServiceConnectConfiguration(config?: ServiceConnectProps) { + if (!this.taskDefinition.defaultContainer) { + throw new Error('Task definition must have at least one container to enable service connect.'); + } + + // Check the implicit enable case; when config isn't specified or namespace isn't specified, we need to check that there is a namespace on the cluster. + if ((!config || !config.namespace) && !this.cluster.defaultCloudMapNamespace) { + throw new Error('Namespace must be defined either in serviceConnectConfig or cluster.defaultCloudMapNamespace'); + } + + // When config isn't specified, return. + if (!config) { + return; + } + + if (!config.services) { + return; + } + let portNames = new Map(); + config.services.forEach(serviceConnectService => { + // port must exist on the task definition + if (!this.taskDefinition.findPortMappingByName(serviceConnectService.portMappingName)) { + throw new Error(`Port Mapping '${serviceConnectService.portMappingName}' does not exist on the task definition.`); + }; + + // Check that no two service connect services use the same discovery name. + const discoveryName = serviceConnectService.discoveryName || serviceConnectService.portMappingName; + if (portNames.get(serviceConnectService.portMappingName)?.includes(discoveryName)) { + throw new Error(`Cannot create multiple services with the discoveryName '${discoveryName}'.`); + } + + let currentDiscoveries = portNames.get(serviceConnectService.portMappingName); + if (!currentDiscoveries) { + portNames.set(serviceConnectService.portMappingName, [discoveryName]); + } else { + currentDiscoveries.push(discoveryName); + portNames.set(serviceConnectService.portMappingName, currentDiscoveries); + } + + // IngressPortOverride should be within the valid port range if it exists. + if (serviceConnectService.ingressPortOverride && !this.isValidPort(serviceConnectService.ingressPortOverride)) { + throw new Error(`ingressPortOverride ${serviceConnectService.ingressPortOverride} is not valid.`); + } + + // clientAlias.port should be within the valid port range + if (serviceConnectService.port && + !this.isValidPort(serviceConnectService.port)) { + throw new Error(`Client Alias port ${serviceConnectService.port} is not valid.`); + } + }); + } + + /** + * Determines if a port is valid + * + * @param port: The port number + * @returns boolean whether the port is valid + */ + private isValidPort(port?: number): boolean { + return !!(port && Number.isInteger(port) && port >= BaseService.MIN_PORT && port <= BaseService.MAX_PORT); + } + /** * The CloudMap service created for this service, if any. */ diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index c3764598114ad..c5730c71be565 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -722,9 +722,42 @@ export class TaskDefinition extends TaskDefinitionBase { } } } + + // Validate that there are no named port mapping conflicts for Service Connect. + const portMappingNames = new Map(); // Map from port mapping name to most recent container it appears in. + this.containers.forEach(container => { + for (const pm of container.portMappings) { + if (pm.name) { + if (portMappingNames.has(pm.name)) { + ret.push(`Port mapping name '${pm.name}' cannot appear in both '${container.containerName}' and '${portMappingNames.get(pm.name)}'`); + } + portMappingNames.set(pm.name, container.containerName); + } + } + }); + + return ret; } + /** + * Determine the existing port mapping for the provided name. + * @param name: port mapping name + * @returns PortMapping for the provided name, if it exists. + */ + public findPortMappingByName(name: string): PortMapping | undefined { + let portMapping; + + this.containers.forEach(container => { + const pm = container.findPortMappingByName(name); + if (pm) { + portMapping = pm; + }; + }); + + return portMapping; + } + /** * Returns the container that match the provided containerName. */ diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index dc42dacb975e0..fbac7e537592a 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -181,6 +181,11 @@ export class Cluster extends Resource implements ICluster { */ private _executeCommandConfiguration?: ExecuteCommandConfiguration; + /** + * CfnCluster instance + */ + private _cfnCluster: CfnCluster; + /** * Constructs a new instance of the Cluster class. */ @@ -212,22 +217,21 @@ export class Cluster extends Resource implements ICluster { this._executeCommandConfiguration = props.executeCommandConfiguration; } - const cluster = new CfnCluster(this, 'Resource', { + this._cfnCluster = new CfnCluster(this, 'Resource', { clusterName: this.physicalName, clusterSettings, configuration: this._executeCommandConfiguration && this.renderExecuteCommandConfiguration(), }); - this.clusterArn = this.getResourceArnAttribute(cluster.attrArn, { + this.clusterArn = this.getResourceArnAttribute(this._cfnCluster.attrArn, { service: 'ecs', resource: 'cluster', resourceName: this.physicalName, }); - this.clusterName = this.getResourceNameAttribute(cluster.ref); + this.clusterName = this.getResourceNameAttribute(this._cfnCluster.ref); this.vpc = props.vpc || new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); - this._defaultCloudMapNamespace = props.defaultCloudMapNamespace !== undefined ? this.addDefaultCloudMapNamespace(props.defaultCloudMapNamespace) : undefined; @@ -306,6 +310,11 @@ export class Cluster extends Resource implements ICluster { }); this._defaultCloudMapNamespace = sdNamespace; + if (options.useForServiceConnect) { + this._cfnCluster.serviceConnectDefaults = { + namespace: options.name, + }; + } return sdNamespace; } @@ -890,6 +899,14 @@ export interface CloudMapNamespaceOptions { * @default VPC of the cluster for Private DNS Namespace, otherwise none */ readonly vpc?: ec2.IVpc; + + /** + * This property specifies whether to set the provided namespace as the service connect default in the cluster properties. + * + * @default false + */ + readonly useForServiceConnect?: boolean; + } enum ContainerInsights { diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index 2e322f84e37cc..8c112a18a3a38 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -456,6 +456,8 @@ export class ContainerDefinition extends Construct { private readonly environment: { [key: string]: string }; + private _namedPorts: Map; + /** * Constructs a new instance of the ContainerDefinition class. */ @@ -475,6 +477,8 @@ export class ContainerDefinition extends Construct { this.imageConfig = props.image.bind(this, this); this.imageName = this.imageConfig.imageName; + this._namedPorts = new Map(); + if (props.logging) { this.logDriverConfig = props.logging.bind(this, this); } @@ -567,6 +571,28 @@ export class ContainerDefinition extends Construct { throw new Error(`Host port (${pm.hostPort}) must be left out or equal to container port ${pm.containerPort} for network mode ${this.taskDefinition.networkMode}`); } } + // No empty strings as port mapping names. + if (pm.name === '') { + throw new Error('Port mapping name cannot be an empty string.'); + } + // Service connect logic. + if (pm.name || pm.appProtocol) { + + // Service connect only supports Awsvpc and Bridge network modes. + if (![NetworkMode.BRIDGE, NetworkMode.AWS_VPC].includes(this.taskDefinition.networkMode)) { + throw new Error(`Service connect related port mapping fields 'name' and 'appProtocol' are not supported for network mode ${this.taskDefinition.networkMode}`); + } + + // Name is not set but App Protocol is; this config is meaningless and we should throw. + if (!pm.name) { + throw new Error('Service connect-related port mapping field \'appProtocol\' cannot be set without \'name\''); + } + + if (this._namedPorts.has(pm.name)) { + throw new Error(`Port mapping name '${pm.name}' already exists on this container`); + } + this._namedPorts.set(pm.name, pm); + } if (this.taskDefinition.networkMode === NetworkMode.BRIDGE) { if (pm.hostPort === undefined) { @@ -576,7 +602,6 @@ export class ContainerDefinition extends Construct { }; } } - return pm; })); } @@ -656,6 +681,13 @@ export class ContainerDefinition extends Construct { return undefined; } + /** + * Returns the port mapping with the given name, if it exists. + */ + public findPortMappingByName(name: string): PortMapping | undefined { + return this._namedPorts.get(name); + } + /** * Whether this container definition references a specific JSON field of a secret * stored in Secrets Manager. @@ -1013,7 +1045,28 @@ export interface PortMapping { * * @default TCP */ - readonly protocol?: Protocol + readonly protocol?: Protocol; + + /** + * The name to give the port mapping. + * + * Name is required in order to use the port mapping with ECS Service Connect. + * This field may only be set when the task definition uses Bridge or Awsvpc network modes. + * + * @default - no port mapping name + */ + readonly name?: string; + + /** + * The protocol used by Service Connect. Valid values are AppProtocol.http, AppProtocol.http2, and + * AppProtocol.grpc. The protocol determines what telemetry will be shown in the ECS Console for + * Service Connect services using this port mapping. + * + * This field may only be set when the task definition uses Bridge or Awsvpc network modes. + * + * @default - no app protocol + */ + readonly appProtocol?: AppProtocol; } /** @@ -1031,11 +1084,41 @@ export enum Protocol { UDP = 'udp', } + +/** + * Service connect app protocol. + */ +export class AppProtocol { + /** + * HTTP app protocol. + */ + public static http = new AppProtocol('http'); + /** + * HTTP2 app protocol. + */ + public static http2 = new AppProtocol('http2'); + /** + * GRPC app protocol. + */ + public static grpc = new AppProtocol('grpc'); + + /** + * Custom value. + */ + public readonly value: string; + + protected constructor(value: string) { + this.value = value; + } +} + function renderPortMapping(pm: PortMapping): CfnTaskDefinition.PortMappingProperty { return { containerPort: pm.containerPort, hostPort: pm.hostPort, protocol: pm.protocol || Protocol.TCP, + appProtocol: pm.appProtocol?.value, + name: pm.name ? pm.name : undefined, }; } diff --git a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts index 350abf82ab58d..5a8717fe585e1 100644 --- a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts @@ -130,4 +130,5 @@ export class AwsLogDriver extends LogDriver { }), }; } + } diff --git a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts index 71c287ea9d011..10863614b7312 100644 --- a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts @@ -1007,6 +1007,23 @@ describe('cluster', () => { }); + test('allows setting cluster ServiceConnectDefaults.Namespace property when useAsServiceConnectDefault is true', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + useForServiceConnect: true, + }); + + // THEN + expect((cluster as any)._cfnCluster.serviceConnectDefaults.namespace).toBe('foo.com'); + }); + /* * TODO:v2.0.0 END OF OBSOLETE BLOCK */ @@ -1278,6 +1295,7 @@ describe('cluster', () => { }); + test('export/import of a cluster with a namespace', () => { // GIVEN const stack1 = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index 526d40fbafba7..a0bfbf217ed2b 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -6,6 +6,7 @@ import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as ecs from '../lib'; +import { AppProtocol } from '../lib'; describe('container definition', () => { describe('When creating a Task Definition', () => { @@ -33,6 +34,91 @@ describe('container definition', () => { }); }); + test('port mapping throws an error when appProtocol is set without name', () => { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + + const container = new ecs.ContainerDefinition(stack, 'Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskDefinition, + memoryLimitMiB: 2048, + portMappings: [ + { + containerPort: 80, + name: 'api', + }, + ], + }); + + // THEN + const expected = [ + { + containerPort: 80, + hostPort: 0, + name: 'api', + }, + ]; + expect(container.portMappings).toEqual(expected); + + expect(() => { + container.addPortMappings( + { + containerPort: 443, + appProtocol: AppProtocol.grpc, + }, + ); + }).toThrow(/Service connect-related port mapping field 'appProtocol' cannot be set without 'name'/); + }); + + test('multiple port mappings of the same name error out', () =>{ + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + + const container = new ecs.ContainerDefinition(stack, 'Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskDefinition, + memoryLimitMiB: 2048, + }); + + // THEN + expect(() => { + container.addPortMappings( + { + containerPort: 80, + name: 'api', + }, + { + containerPort: 443, + name: 'api', + }, + ); + }).toThrow(/Port mapping name 'api' already exists on this container/); + }); + + test('empty string port mapping name throws', () => { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + + const container = new ecs.ContainerDefinition(stack, 'Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskDefinition, + memoryLimitMiB: 2048, + }); + + // THEN + expect(() => { + container.addPortMappings( + { + containerPort: 80, + name: '', + }, + ); + }).toThrow(); + }); + test('add a container using all props', () => { // GIVEN const app = new cdk.App({ context: { [cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: false } }); @@ -397,6 +483,28 @@ describe('container definition', () => { container.addLink(logger); }).toThrow(); }); + + test('service connect fields are not allowed', () => { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { + networkMode: ecs.NetworkMode.HOST, + }); + + // THEN + expect(() => { + taskDefinition.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + memoryLimitMiB: 2048, + portMappings: [ + { + name: 'api', + containerPort: 80, + }, + ], + }); + }).toThrow('Service connect related port mapping fields \'name\' and \'appProtocol\' are not supported for network mode host'); + }); }); describe('With network mode Bridge', () => { diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index 5823ed2e6cbce..a7647f8e3fa4a 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -14,7 +14,7 @@ import { App } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { ECS_ARN_FORMAT_INCLUDES_CLUSTER_NAME } from '@aws-cdk/cx-api'; import * as ecs from '../../lib'; -import { DeploymentControllerType, LaunchType, PropagatedTagSource } from '../../lib/base/base-service'; +import { DeploymentControllerType, LaunchType, PropagatedTagSource, ServiceConnectProps } from '../../lib/base/base-service'; import { addDefaultCapacityProvider } from '../util'; describe('fargate service', () => { @@ -959,6 +959,420 @@ describe('fargate service', () => { }); }); + describe('when enabling service connect', () => { + describe('when validating service connect configurations', () => { + + let service: ecs.FargateService; + + beforeEach(() => { + // 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'); + + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }); + + service = new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + }); + }); + + test('throws an exception if serviceconnectservice.port is a string and it does not exists on the task definition', () => { + // GIVEN + const config: ServiceConnectProps = { + services: [ + { + portMappingName: '100', + dnsName: 'backend.prod', + }, + ], + namespace: 'test namespace', + }; + expect(() => { + service.enableServiceConnect(config); + }).toThrowError(/Port Mapping '100' does not exist on the task definition./); + }); + + test('throws an exception when adding multiple services without different discovery names', () => { + // GIVEN + service.taskDefinition.addContainer('mobile', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + portMappings: [ + { + containerPort: 100, + name: 'abc', + }, + ], + }); + const config: ServiceConnectProps = { + services: [ + { + portMappingName: 'abc', + dnsName: 'backend.prod', + port: 5005, + }, + { + portMappingName: 'abc', + dnsName: 'backend.prod.local', + }, + ], + namespace: 'test namespace', + }; + expect(() => { + service.enableServiceConnect(config); + }).toThrowError(/Cannot create multiple services with the discoveryName 'abc'./); + }); + + test('throws an exception if ingressPortOverride is not valid.', () => { + // GIVEN + service.taskDefinition.addContainer('mobile', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + portMappings: [ + { + containerPort: 100, + name: '100', + }, + ], + }); + const config: ServiceConnectProps = { + services: [ + { + portMappingName: '100', + dnsName: 'backend.prod', + port: 5005, + ingressPortOverride: 100000, + }, + ], + namespace: 'test namespace', + }; + expect(() => { + service.enableServiceConnect(config); + }).toThrowError(/ingressPortOverride 100000 is not valid./); + }); + + test('throws an exception if Client Alias port is not valid', () => { + // GIVEN + service.taskDefinition.addContainer('mobile', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + portMappings: [ + { + containerPort: 100, + name: '100', + }, + ], + }); + const config: ServiceConnectProps = { + services: [ + { + portMappingName: '100', + dnsName: 'backend.prod', + port: 100000, + ingressPortOverride: 3000, + }, + ], + namespace: 'test namespace', + }; + expect(() => { + service.enableServiceConnect(config); + }).toThrowError(/Client Alias port 100000 is not valid./); + }); + }); + + describe('when creating a FargateService with service connect', () => { + + let service: ecs.FargateService; + let stack: cdk.Stack; + let cluster: ecs.Cluster; + + beforeEach(() => { + // GIVEN + stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + portMappings: [ + { + containerPort: 80, + name: 'api', + }, + ], + }); + + service = new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + }); + }); + + test('service connect cannot be enabled twice', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect(); + + // THEN + + expect(() => { + service.enableServiceConnect({}); + }).toThrow('Service connect configuration cannot be specified more than once.'); + }); + + test('client alias port is defaulted to containerport', () => { + service.enableServiceConnect({ + namespace: 'cool', + services: [ + { + portMappingName: 'api', + }, + ], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + Services: [ + { + PortName: 'api', + ClientAliases: [ + { + Port: 80, + }, + ], + }, + ], + }, + }); + }); + + test('with explicit enable', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect({}); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + }, + }); + }); + + test('with explicit enable and no props', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect(); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + }, + }); + }); + + test('explicit enable and non default namespace', () => { + // WHEN + const ns = new cloudmap.HttpNamespace(stack, 'ns', { + name: 'cool', + }); + service.enableServiceConnect({ + namespace: ns.namespaceName, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + }, + }); + }); + + test('namespace inferred from cluster', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect({}); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + }, + }); + }); + + test('namespace inferred from cluster; empty props', () => { + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect(); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + }, + }); + }); + + test('no namespace errors out', () => { + // THEN + expect(() => { + service.enableServiceConnect({}); + }).toThrow(); + }); + + test('error when enabling service connect with no container', () => { + // GIVEN + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'td2'); + const svc = new ecs.FargateService(stack, 'svc2', { + cluster, + taskDefinition, + }); + expect(() => { + svc.enableServiceConnect({ + logDriver: ecs.LogDrivers.awsLogs({ + streamPrefix: 'sc', + }), + }); + }).toThrow('Task definition must have at least one container to enable service connect.'); + }); + + test('with all options exercised', () => { + // WHEN + new cloudmap.HttpNamespace(stack, 'httpnamespace', { + name: 'cool', + }); + service.enableServiceConnect({ + services: [ + { + portMappingName: 'api', + discoveryName: 'svc', + ingressPortOverride: 1000, + port: 80, + dnsName: 'api', + }, + ], + namespace: 'cool', + logDriver: ecs.LogDrivers.awsLogs({ + streamPrefix: 'sc', + }), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + Services: [ + { + PortName: 'api', + IngressPortOverride: 1000, + DiscoveryName: 'svc', + ClientAliases: [ + { + Port: 80, + DnsName: 'api', + }, + ], + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-stream-prefix': 'sc', + }, + }, + }, + }); + }); + + test('with no alias name', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect({ + services: [ + { + portMappingName: 'api', + port: 80, + }, + ], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + Services: [ + { + PortName: 'api', + ClientAliases: [ + { + Port: 80, + }, + ], + }, + ], + }, + }); + }); + + test('with no alias specified', () => { + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'cool', + }); + service.enableServiceConnect({ + services: [ + { + portMappingName: 'api', + }, + ], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceConnectConfiguration: { + Enabled: true, + Namespace: 'cool', + Services: [ + { + PortName: 'api', + ClientAliases: [ + { + Port: 80, + }, + ], + }, + ], + }, + }); + }); + }); + }); + describe('When setting up a health check', () => { test('grace period is respected', () => { // GIVEN diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.assets.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.assets.json new file mode 100644 index 0000000000000..e61034dcca739 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "ServiceConnectDefaultTestDeployAssert88F6A66F.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.template.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/ServiceConnectDefaultTestDeployAssert88F6A66F.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.assets.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.assets.json new file mode 100644 index 0000000000000..a8a2db0f50a21 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "e9571a8d510167c0dab7107a964034a2a26011d7b8b714adbd3cc0a445a68cfa": { + "source": { + "path": "aws-ecs-service-connect.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "e9571a8d510167c0dab7107a964034a2a26011d7b8b714adbd3cc0a445a68cfa.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.template.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.template.json new file mode 100644 index 0000000000000..3260a668d1ea1 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/aws-ecs-service-connect.template.json @@ -0,0 +1,659 @@ +{ + "Resources": { + "EcsCluster97242B84": { + "Type": "AWS::ECS::Cluster", + "Properties": { + "ServiceConnectDefaults": { + "Namespace": "scorekeep.com" + } + } + }, + "EcsClusterVpc779914AB": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc" + } + ] + } + }, + "EcsClusterVpcPublicSubnet1Subnet4AC37B0F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "EcsClusterVpcPublicSubnet1RouteTable4AE3113D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "EcsClusterVpcPublicSubnet1RouteTableAssociation49C4CDBB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPublicSubnet1RouteTable4AE3113D" + }, + "SubnetId": { + "Ref": "EcsClusterVpcPublicSubnet1Subnet4AC37B0F" + } + } + }, + "EcsClusterVpcPublicSubnet1DefaultRoute8C7EFC96": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPublicSubnet1RouteTable4AE3113D" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + }, + "DependsOn": [ + "EcsClusterVpcVPCGW944296C0" + ] + }, + "EcsClusterVpcPublicSubnet1EIP2D3759A3": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "EcsClusterVpcPublicSubnet1NATGateway2F1E7764": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "EcsClusterVpcPublicSubnet1Subnet4AC37B0F" + }, + "AllocationId": { + "Fn::GetAtt": [ + "EcsClusterVpcPublicSubnet1EIP2D3759A3", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "EcsClusterVpcPublicSubnet1DefaultRoute8C7EFC96", + "EcsClusterVpcPublicSubnet1RouteTableAssociation49C4CDBB" + ] + }, + "EcsClusterVpcPublicSubnet2Subnet4A959A4C": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "EcsClusterVpcPublicSubnet2RouteTableAssociationE4D42FC1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5" + }, + "SubnetId": { + "Ref": "EcsClusterVpcPublicSubnet2Subnet4A959A4C" + } + } + }, + "EcsClusterVpcPublicSubnet2DefaultRoute048730F7": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + }, + "DependsOn": [ + "EcsClusterVpcVPCGW944296C0" + ] + }, + "EcsClusterVpcPublicSubnet2EIP26E3EEEF": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "EcsClusterVpcPublicSubnet2NATGatewayBD015416": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "EcsClusterVpcPublicSubnet2Subnet4A959A4C" + }, + "AllocationId": { + "Fn::GetAtt": [ + "EcsClusterVpcPublicSubnet2EIP26E3EEEF", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "EcsClusterVpcPublicSubnet2DefaultRoute048730F7", + "EcsClusterVpcPublicSubnet2RouteTableAssociationE4D42FC1" + ] + }, + "EcsClusterVpcPrivateSubnet1SubnetFAB0E487": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1" + } + ] + } + }, + "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1" + } + ] + } + }, + "EcsClusterVpcPrivateSubnet1RouteTableAssociationF4E8ACD7": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE" + }, + "SubnetId": { + "Ref": "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + } + } + }, + "EcsClusterVpcPrivateSubnet1DefaultRoute0239F5D0": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EcsClusterVpcPublicSubnet1NATGateway2F1E7764" + } + } + }, + "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2" + } + ] + } + }, + "EcsClusterVpcPrivateSubnet2RouteTable1D430E45": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2" + } + ] + } + }, + "EcsClusterVpcPrivateSubnet2RouteTableAssociation329A2412": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPrivateSubnet2RouteTable1D430E45" + }, + "SubnetId": { + "Ref": "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + } + }, + "EcsClusterVpcPrivateSubnet2DefaultRoute27221D27": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsClusterVpcPrivateSubnet2RouteTable1D430E45" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EcsClusterVpcPublicSubnet2NATGatewayBD015416" + } + } + }, + "EcsClusterVpcIGW3663B083": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-service-connect/EcsCluster/Vpc" + } + ] + } + }, + "EcsClusterVpcVPCGW944296C0": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "InternetGatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + } + }, + "EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F": { + "Type": "AWS::ServiceDiscovery::PrivateDnsNamespace", + "Properties": { + "Name": "scorekeep.com", + "Vpc": { + "Ref": "EcsClusterVpc779914AB" + } + } + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "TaskDefcontainerLogGroupAB21CBAF" + }, + "awslogs-stream-prefix": "web", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "web", + "PortMappings": [ + { + "AppProtocol": "http2", + "ContainerPort": 80, + "Name": "api", + "Protocol": "tcp" + } + ] + } + ], + "Cpu": "1024", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "TaskDefExecutionRoleB4775C97", + "Arn" + ] + }, + "Family": "awsecsserviceconnectTaskDefEE77A948", + "Memory": "2048", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "TaskDefcontainerLogGroupAB21CBAF": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "TaskDefExecutionRoleB4775C97": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDefExecutionRoleDefaultPolicy0DBB737A": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TaskDefcontainerLogGroupAB21CBAF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "svcLogGroup25CAF347", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TaskDefExecutionRoleDefaultPolicy0DBB737A", + "Roles": [ + { + "Ref": "TaskDefExecutionRoleB4775C97" + } + ] + } + }, + "svcService376F2D22": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsCluster97242B84" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "svcSecurityGroup205CC2DA", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + }, + { + "Ref": "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + ] + } + }, + "ServiceConnectConfiguration": { + "Enabled": true, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "svcLogGroup25CAF347" + }, + "awslogs-stream-prefix": "sc", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Namespace": "scorekeep.com", + "Services": [ + { + "ClientAliases": [ + { + "DnsName": "api", + "Port": 80 + } + ], + "PortName": "api" + } + ] + }, + "TaskDefinition": { + "Ref": "TaskDef54694570" + } + } + }, + "svcLogGroup25CAF347": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "svcSecurityGroup205CC2DA": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-service-connect/svc/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "EcsClusterVpc779914AB" + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/cdk.out b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/integ.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/integ.json new file mode 100644 index 0000000000000..4d824c96af6ed --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "ServiceConnect/DefaultTest": { + "stacks": [ + "aws-ecs-service-connect" + ], + "assertionStack": "ServiceConnect/DefaultTest/DeployAssert", + "assertionStackName": "ServiceConnectDefaultTestDeployAssert88F6A66F" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/manifest.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/manifest.json new file mode 100644 index 0000000000000..e95e28224bb9e --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/manifest.json @@ -0,0 +1,306 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-ecs-service-connect.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-ecs-service-connect.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-ecs-service-connect": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-ecs-service-connect.template.json", + "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}/e9571a8d510167c0dab7107a964034a2a26011d7b8b714adbd3cc0a445a68cfa.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-ecs-service-connect.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-ecs-service-connect.assets" + ], + "metadata": { + "/aws-ecs-service-connect/EcsCluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsCluster97242B84" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpc779914AB" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1Subnet4AC37B0F" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1RouteTable4AE3113D" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1RouteTableAssociation49C4CDBB" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1DefaultRoute8C7EFC96" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1EIP2D3759A3" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet1NATGateway2F1E7764" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2Subnet4A959A4C" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2RouteTableAssociationE4D42FC1" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2DefaultRoute048730F7" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2EIP26E3EEEF" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPublicSubnet2NATGatewayBD015416" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet1RouteTableAssociationF4E8ACD7" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet1DefaultRoute0239F5D0" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet2RouteTable1D430E45" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet2RouteTableAssociation329A2412" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcPrivateSubnet2DefaultRoute27221D27" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcIGW3663B083" + } + ], + "/aws-ecs-service-connect/EcsCluster/Vpc/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterVpcVPCGW944296C0" + } + ], + "/aws-ecs-service-connect/EcsCluster/DefaultServiceDiscoveryNamespace/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F" + } + ], + "/aws-ecs-service-connect/TaskDef/TaskRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDefTaskRole1EDB4A67" + } + ], + "/aws-ecs-service-connect/TaskDef/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDef54694570", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" + ] + } + ], + "/aws-ecs-service-connect/TaskDef/container/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDefcontainerLogGroupAB21CBAF" + } + ], + "/aws-ecs-service-connect/TaskDef/ExecutionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDefExecutionRoleB4775C97" + } + ], + "/aws-ecs-service-connect/TaskDef/ExecutionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDefExecutionRoleDefaultPolicy0DBB737A" + } + ], + "/aws-ecs-service-connect/svc/Service": [ + { + "type": "aws:cdk:logicalId", + "data": "svcService376F2D22" + } + ], + "/aws-ecs-service-connect/svc/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "svcLogGroup25CAF347" + } + ], + "/aws-ecs-service-connect/svc/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "svcSecurityGroup205CC2DA" + } + ], + "/aws-ecs-service-connect/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-ecs-service-connect/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-ecs-service-connect" + }, + "ServiceConnectDefaultTestDeployAssert88F6A66F.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "ServiceConnectDefaultTestDeployAssert88F6A66F.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "ServiceConnectDefaultTestDeployAssert88F6A66F": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "ServiceConnectDefaultTestDeployAssert88F6A66F.template.json", + "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}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "ServiceConnectDefaultTestDeployAssert88F6A66F.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "ServiceConnectDefaultTestDeployAssert88F6A66F.assets" + ], + "metadata": { + "/ServiceConnect/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/ServiceConnect/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "ServiceConnect/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/tree.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/tree.json new file mode 100644 index 0000000000000..38038e8915793 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.js.snapshot/tree.json @@ -0,0 +1,1128 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + }, + "aws-ecs-service-connect": { + "id": "aws-ecs-service-connect", + "path": "aws-ecs-service-connect", + "children": { + "EcsCluster": { + "id": "EcsCluster", + "path": "aws-ecs-service-connect/EcsCluster", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/EcsCluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::Cluster", + "aws:cdk:cloudformation:props": { + "serviceConnectDefaults": { + "namespace": "scorekeep.com" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.CfnCluster", + "version": "2.45.0" + } + }, + "Vpc": { + "id": "Vpc", + "path": "aws-ecs-service-connect/EcsCluster/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "version": "2.45.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "2.45.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "2.45.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "2.45.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPublicSubnet1RouteTable4AE3113D" + }, + "subnetId": { + "Ref": "EcsClusterVpcPublicSubnet1Subnet4AC37B0F" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "2.45.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPublicSubnet1RouteTable4AE3113D" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "version": "2.45.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnEIP", + "version": "2.45.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "EcsClusterVpcPublicSubnet1Subnet4AC37B0F" + }, + "allocationId": { + "Fn::GetAtt": [ + "EcsClusterVpcPublicSubnet1EIP2D3759A3", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PublicSubnet", + "version": "2.45.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.64.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "2.45.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "2.45.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "2.45.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5" + }, + "subnetId": { + "Ref": "EcsClusterVpcPublicSubnet2Subnet4A959A4C" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "2.45.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPublicSubnet2RouteTable89A2F6C5" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "version": "2.45.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnEIP", + "version": "2.45.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "EcsClusterVpcPublicSubnet2Subnet4A959A4C" + }, + "allocationId": { + "Fn::GetAtt": [ + "EcsClusterVpcPublicSubnet2EIP26E3EEEF", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PublicSubnet", + "version": "2.45.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "2.45.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "2.45.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "2.45.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE" + }, + "subnetId": { + "Ref": "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "2.45.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPrivateSubnet1RouteTable2EA148EE" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "EcsClusterVpcPublicSubnet1NATGateway2F1E7764" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "2.45.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.192.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "2.45.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "2.45.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "2.45.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPrivateSubnet2RouteTable1D430E45" + }, + "subnetId": { + "Ref": "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "2.45.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "EcsClusterVpcPrivateSubnet2RouteTable1D430E45" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "EcsClusterVpcPublicSubnet2NATGatewayBD015416" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "2.45.0" + } + }, + "IGW": { + "id": "IGW", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-service-connect/EcsCluster/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnInternetGateway", + "version": "2.45.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "aws-ecs-service-connect/EcsCluster/Vpc/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + }, + "internetGatewayId": { + "Ref": "EcsClusterVpcIGW3663B083" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPCGatewayAttachment", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.Vpc", + "version": "2.45.0" + } + }, + "DefaultServiceDiscoveryNamespace": { + "id": "DefaultServiceDiscoveryNamespace", + "path": "aws-ecs-service-connect/EcsCluster/DefaultServiceDiscoveryNamespace", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/EcsCluster/DefaultServiceDiscoveryNamespace/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ServiceDiscovery::PrivateDnsNamespace", + "aws:cdk:cloudformation:props": { + "name": "scorekeep.com", + "vpc": { + "Ref": "EcsClusterVpc779914AB" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicediscovery.CfnPrivateDnsNamespace", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicediscovery.PrivateDnsNamespace", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.Cluster", + "version": "2.45.0" + } + }, + "TaskDef": { + "id": "TaskDef", + "path": "aws-ecs-service-connect/TaskDef", + "children": { + "TaskRole": { + "id": "TaskRole", + "path": "aws-ecs-service-connect/TaskDef/TaskRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/TaskDef/TaskRole/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": "@aws-cdk/aws-iam.CfnRole", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "2.45.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/TaskDef/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::TaskDefinition", + "aws:cdk:cloudformation:props": { + "containerDefinitions": [ + { + "essential": true, + "image": "amazon/amazon-ecs-sample", + "name": "web", + "portMappings": [ + { + "containerPort": 80, + "protocol": "tcp", + "appProtocol": "http2", + "name": "api" + } + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": { + "Ref": "TaskDefcontainerLogGroupAB21CBAF" + }, + "awslogs-stream-prefix": "web", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + } + } + ], + "cpu": "1024", + "executionRoleArn": { + "Fn::GetAtt": [ + "TaskDefExecutionRoleB4775C97", + "Arn" + ] + }, + "family": "awsecsserviceconnectTaskDefEE77A948", + "memory": "2048", + "networkMode": "awsvpc", + "requiresCompatibilities": [ + "FARGATE" + ], + "taskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.CfnTaskDefinition", + "version": "2.45.0" + } + }, + "container": { + "id": "container", + "path": "aws-ecs-service-connect/TaskDef/container", + "children": { + "LogGroup": { + "id": "LogGroup", + "path": "aws-ecs-service-connect/TaskDef/container/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/TaskDef/container/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.ContainerDefinition", + "version": "2.45.0" + } + }, + "ExecutionRole": { + "id": "ExecutionRole", + "path": "aws-ecs-service-connect/TaskDef/ExecutionRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/TaskDef/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": "@aws-cdk/aws-iam.CfnRole", + "version": "2.45.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-ecs-service-connect/TaskDef/ExecutionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/TaskDef/ExecutionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TaskDefcontainerLogGroupAB21CBAF", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "svcLogGroup25CAF347", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "TaskDefExecutionRoleDefaultPolicy0DBB737A", + "roles": [ + { + "Ref": "TaskDefExecutionRoleB4775C97" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.FargateTaskDefinition", + "version": "2.45.0" + } + }, + "svc": { + "id": "svc", + "path": "aws-ecs-service-connect/svc", + "children": { + "Service": { + "id": "Service", + "path": "aws-ecs-service-connect/svc/Service", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::Service", + "aws:cdk:cloudformation:props": { + "cluster": { + "Ref": "EcsCluster97242B84" + }, + "deploymentConfiguration": { + "maximumPercent": 200, + "minimumHealthyPercent": 50 + }, + "enableEcsManagedTags": false, + "launchType": "FARGATE", + "networkConfiguration": { + "awsvpcConfiguration": { + "assignPublicIp": "DISABLED", + "subnets": [ + { + "Ref": "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + }, + { + "Ref": "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + ], + "securityGroups": [ + { + "Fn::GetAtt": [ + "svcSecurityGroup205CC2DA", + "GroupId" + ] + } + ] + } + }, + "serviceConnectConfiguration": { + "enabled": true, + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": { + "Ref": "svcLogGroup25CAF347" + }, + "awslogs-stream-prefix": "sc", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "namespace": "scorekeep.com", + "services": [ + { + "portName": "api", + "clientAliases": [ + { + "dnsName": "api", + "port": 80 + } + ] + } + ] + }, + "taskDefinition": { + "Ref": "TaskDef54694570" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.CfnService", + "version": "2.45.0" + } + }, + "LogGroup": { + "id": "LogGroup", + "path": "aws-ecs-service-connect/svc/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/svc/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "2.45.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-ecs-service-connect/svc/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-service-connect/svc/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "aws-ecs-service-connect/svc/SecurityGroup", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "EcsClusterVpc779914AB" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ecs.FargateService", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "2.45.0" + } + }, + "ServiceConnect": { + "id": "ServiceConnect", + "path": "ServiceConnect", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "ServiceConnect/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "ServiceConnect/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "ServiceConnect/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "2.45.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "2.45.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.ts b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.ts new file mode 100644 index 0000000000000..391781f42ce89 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.service-connect.ts @@ -0,0 +1,63 @@ +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { Construct } from 'constructs'; +import * as ecs from '../../lib'; + + +class ServiceConnect extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + const cluster = new ecs.Cluster(this, 'EcsCluster', { + defaultCloudMapNamespace: { + name: 'scorekeep.com', + useForServiceConnect: true, + }, + }); + + const td = new ecs.FargateTaskDefinition(this, 'TaskDef', { + cpu: 1024, + memoryLimitMiB: 2048, + }); + + td.addContainer('container', { + containerName: 'web', + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + portMappings: [ + { + name: 'api', + containerPort: 80, + appProtocol: ecs.AppProtocol.http2, + }, + ], + logging: ecs.LogDrivers.awsLogs({ + streamPrefix: 'web', + }), + }); + + new ecs.FargateService(this, 'svc', { + taskDefinition: td, + cluster: cluster, + serviceConnectConfiguration: { + services: [ + { + portMappingName: 'api', + dnsName: 'api', + port: 80, + }, + ], + logDriver: ecs.LogDrivers.awsLogs({ + streamPrefix: 'sc', + }), + }, + }); + } +} + +const app = new cdk.App(); +const stack = new ServiceConnect(app, 'aws-ecs-service-connect'); + +new integ.IntegTest(app, 'ServiceConnect', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts index 8629eea6342fb..9b358d197a128 100644 --- a/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts @@ -199,6 +199,36 @@ describe('task definition', () => { }, }); }); + + test('A task definition where multiple containers have a port mapping with the same name throws an error', () =>{ + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + + new ecs.ContainerDefinition(stack, 'Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskDefinition, + memoryLimitMiB: 2048, + portMappings: [{ + containerPort: 80, + name: 'api', + }], + }); + new ecs.ContainerDefinition(stack, 'Container2', { + taskDefinition, + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + memoryLimitMiB: 2048, + portMappings: [{ + containerPort: 8080, + name: 'api', + }], + }); + + // THEN + expect(() => { + Template.fromStack(stack); + }).toThrow("Port mapping name 'api' cannot appear in both 'Container2' and 'Container'"); + }); }); describe('When importing from an existing Task definition', () => { diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json index c59817b4c9ee3..684ae56780816 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json @@ -1,5 +1,5 @@ { - "$version": "97.0.0", + "$version": "98.0.0", "PropertyTypes": { "AWS::ECS::CapacityProvider.AutoScalingGroupProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-capacityprovider-autoscalinggroupprovider.html", @@ -168,6 +168,17 @@ } } }, + "AWS::ECS::Cluster.ServiceConnectDefaults": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-serviceconnectdefaults.html", + "Properties": { + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-serviceconnectdefaults.html#cfn-ecs-cluster-serviceconnectdefaults-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::ClusterCapacityProviderAssociations.CapacityProviderStrategy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-clustercapacityproviderassociations-capacityproviderstrategy.html", "Properties": { @@ -319,6 +330,31 @@ } } }, + "AWS::ECS::Service.LogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html", + "Properties": { + "LogDriver": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-logdriver", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-options", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "SecretOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-secretoptions", + "ItemType": "Secret", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::Service.NetworkConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-networkconfiguration.html", "Properties": { @@ -364,6 +400,100 @@ } } }, + "AWS::ECS::Service.Secret": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html#cfn-ecs-service-secret-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ValueFrom": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html#cfn-ecs-service-secret-valuefrom", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectClientAlias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html", + "Properties": { + "DnsName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html#cfn-ecs-service-serviceconnectclientalias-dnsname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html#cfn-ecs-service-serviceconnectclientalias-port", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "LogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-logconfiguration", + "Required": false, + "Type": "LogConfiguration", + "UpdateType": "Mutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Services": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-services", + "ItemType": "ServiceConnectService", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectService": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html", + "Properties": { + "ClientAliases": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-clientaliases", + "ItemType": "ServiceConnectClientAlias", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DiscoveryName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-discoveryname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IngressPortOverride": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-ingressportoverride", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "PortName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-portname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::Service.ServiceRegistry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html", "Properties": { @@ -1049,6 +1179,12 @@ "AWS::ECS::TaskDefinition.PortMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html", "Properties": { + "AppProtocol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-portmapping-appprotocol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "ContainerPort": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-containerdefinition-portmappings-containerport", "PrimitiveType": "Integer", @@ -1061,6 +1197,12 @@ "Required": false, "UpdateType": "Immutable" }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-portmapping-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Protocol": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-containerdefinition-portmappings-sourcevolume", "PrimitiveType": "String", @@ -1461,6 +1603,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "ServiceConnectDefaults": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-serviceconnectdefaults", + "Required": false, + "Type": "ServiceConnectDefaults", + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-tags", "ItemType": "Tag", @@ -1636,6 +1784,12 @@ "Required": false, "UpdateType": "Immutable" }, + "ServiceConnectConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-serviceconnectconfiguration", + "Required": false, + "Type": "ServiceConnectConfiguration", + "UpdateType": "Mutable" + }, "ServiceName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-servicename", "PrimitiveType": "String", From d04a359e077fab8cb834f163cbacbaf83139f890 Mon Sep 17 00:00:00 2001 From: Madeline Kusters <80541297+madeline-k@users.noreply.github.com> Date: Sun, 27 Nov 2022 11:52:13 -0800 Subject: [PATCH 2/3] chore(release): 2.52.0 --- CHANGELOG.v2.alpha.md | 2 ++ CHANGELOG.v2.md | 7 +++++++ version.v2.json | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.v2.alpha.md b/CHANGELOG.v2.alpha.md index 8aa330f28597c..71d43022ab3d3 100644 --- a/CHANGELOG.v2.alpha.md +++ b/CHANGELOG.v2.alpha.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.52.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.51.1-alpha.0...v2.52.0-alpha.0) (2022-11-27) + ## [2.51.1-alpha.0](https://github.com/aws/aws-cdk/compare/v2.51.0-alpha.0...v2.51.1-alpha.0) (2022-11-18) ## [2.51.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.50.0-alpha.0...v2.51.0-alpha.0) (2022-11-18) diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index 805bb39067fb3..e8d14027ae95e 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.52.0](https://github.com/aws/aws-cdk/compare/v2.51.1...v2.52.0) (2022-11-27) + + +### Features + +* **ecs:** enable Amazon ECS Service Connect ([96ec613](https://github.com/aws/aws-cdk/commit/96ec6139e1ad7637466e95b71e824965b081154f)) + ## [2.51.1](https://github.com/aws/aws-cdk/compare/v2.51.0...v2.51.1) (2022-11-18) diff --git a/version.v2.json b/version.v2.json index a0fe876f996a8..12eecc021f473 100644 --- a/version.v2.json +++ b/version.v2.json @@ -1,4 +1,4 @@ { - "version": "2.51.1", - "alphaVersion": "2.51.1-alpha.0" + "version": "2.52.0", + "alphaVersion": "2.52.0-alpha.0" } \ No newline at end of file From b50a5e287962335f8678cddc2d2f8a7f3d83bac0 Mon Sep 17 00:00:00 2001 From: Madeline Kusters <80541297+madeline-k@users.noreply.github.com> Date: Sun, 27 Nov 2022 15:17:31 -0800 Subject: [PATCH 3/3] chore: Merge conflicts - update cfn spec to what is checked into main --- .../000_cfn/000_official/000_AWS_ECS.json | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json index bdb8aa0798bd4..08d6ac23184a1 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/000_official/000_AWS_ECS.json @@ -168,6 +168,17 @@ } } }, + "AWS::ECS::Cluster.ServiceConnectDefaults": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-serviceconnectdefaults.html", + "Properties": { + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-serviceconnectdefaults.html#cfn-ecs-cluster-serviceconnectdefaults-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::ClusterCapacityProviderAssociations.CapacityProviderStrategy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-clustercapacityproviderassociations-capacityproviderstrategy.html", "Properties": { @@ -319,6 +330,31 @@ } } }, + "AWS::ECS::Service.LogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html", + "Properties": { + "LogDriver": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-logdriver", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-options", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "SecretOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-logconfiguration.html#cfn-ecs-service-logconfiguration-secretoptions", + "ItemType": "Secret", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::Service.NetworkConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-networkconfiguration.html", "Properties": { @@ -364,6 +400,100 @@ } } }, + "AWS::ECS::Service.Secret": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html#cfn-ecs-service-secret-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ValueFrom": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-secret.html#cfn-ecs-service-secret-valuefrom", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectClientAlias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html", + "Properties": { + "DnsName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html#cfn-ecs-service-serviceconnectclientalias-dnsname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectclientalias.html#cfn-ecs-service-serviceconnectclientalias-port", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "LogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-logconfiguration", + "Required": false, + "Type": "LogConfiguration", + "UpdateType": "Mutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Services": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectconfiguration.html#cfn-ecs-service-serviceconnectconfiguration-services", + "ItemType": "ServiceConnectService", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ECS::Service.ServiceConnectService": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html", + "Properties": { + "ClientAliases": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-clientaliases", + "ItemType": "ServiceConnectClientAlias", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DiscoveryName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-discoveryname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IngressPortOverride": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-ingressportoverride", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "PortName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceconnectservice.html#cfn-ecs-service-serviceconnectservice-portname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::ECS::Service.ServiceRegistry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-serviceregistry.html", "Properties": { @@ -1049,6 +1179,12 @@ "AWS::ECS::TaskDefinition.PortMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html", "Properties": { + "AppProtocol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-portmapping-appprotocol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "ContainerPort": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-containerdefinition-portmappings-containerport", "PrimitiveType": "Integer", @@ -1061,6 +1197,12 @@ "Required": false, "UpdateType": "Immutable" }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-portmapping-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Protocol": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html#cfn-ecs-taskdefinition-containerdefinition-portmappings-sourcevolume", "PrimitiveType": "String", @@ -1461,6 +1603,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "ServiceConnectDefaults": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-serviceconnectdefaults", + "Required": false, + "Type": "ServiceConnectDefaults", + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-tags", "ItemType": "Tag", @@ -1636,6 +1784,12 @@ "Required": false, "UpdateType": "Immutable" }, + "ServiceConnectConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-serviceconnectconfiguration", + "Required": false, + "Type": "ServiceConnectConfiguration", + "UpdateType": "Mutable" + }, "ServiceName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-servicename", "PrimitiveType": "String",