From fbb22a90e228bce020808604649235df3028a1bb Mon Sep 17 00:00:00 2001 From: Austin Ely Date: Wed, 30 Nov 2022 19:51:35 +0000 Subject: [PATCH] fix: ensure dependencies are correctly rendered --- API.md | 2 - src/extensions/aliased-port.ts | 16 +- src/service.ts | 1 + .../aws-ecs-integ.assets.json | 4 +- .../aws-ecs-integ.template.json | 141 +++++++++++++++++- test/aliased-port.integ.ts | 22 ++- 6 files changed, 176 insertions(+), 10 deletions(-) diff --git a/API.md b/API.md index 94190d63..df21b1dc 100644 --- a/API.md +++ b/API.md @@ -2193,8 +2193,6 @@ create any final resources which might depend on the service itself. - *Type:* aws-cdk-lib.aws_ecs.Ec2Service | aws-cdk-lib.aws_ecs.FargateService -The generated service. - --- ##### `useTaskDefinition` diff --git a/src/extensions/aliased-port.ts b/src/extensions/aliased-port.ts index b8e31ae7..ac14b37d 100644 --- a/src/extensions/aliased-port.ts +++ b/src/extensions/aliased-port.ts @@ -1,4 +1,5 @@ import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as cloudmap from 'aws-cdk-lib/aws-servicediscovery'; import { Construct } from 'constructs'; import { Service } from '../service'; import { Container } from './container'; @@ -47,7 +48,7 @@ export class AliasedPortExtension extends ServiceExtension { protected alias: string; protected aliasPort?: number; protected appProtocol?: ecs.AppProtocol; - protected namespace?: string; + protected namespace?: cloudmap.INamespace; constructor(props: AliasedPortProps) { super('aliasedPort'); @@ -62,12 +63,12 @@ export class AliasedPortExtension extends ServiceExtension { this.scope = scope; // If there isn't a default cloudmap namespace on the cluster, create a private HTTP namespace for SC. - if (!this.parentService.cluster.defaultCloudMapNamespace) { + if (!this.parentService.environment.cluster.defaultCloudMapNamespace) { this.parentService.environment.addDefaultCloudMapNamespace({ name: this.parentService.environment.id, }); } - this.namespace = this.parentService.environment.cluster.defaultCloudMapNamespace?.namespaceName; + this.namespace = this.parentService.environment.cluster.defaultCloudMapNamespace as cloudmap.INamespace; } public addHooks(): void { @@ -84,7 +85,7 @@ export class AliasedPortExtension extends ServiceExtension { } public modifyServiceProps(props: ServiceBuild): ServiceBuild { - if (props.serviceConnectConfiguration && props.serviceConnectConfiguration.namespace !== this.namespace) { + if (props.serviceConnectConfiguration && props.serviceConnectConfiguration.namespace !== this.namespace?.namespaceName) { throw new Error('Service connect cannot be enabled with two different namespaces.'); } @@ -131,6 +132,13 @@ export class AliasedPortExtension extends ServiceExtension { }, }; } + + public useService(service: ecs.Ec2Service | ecs.FargateService): void { + if (!this.namespace) { + throw new Error('Environment must have a default Cloudmap namespace to enable Service Connect.'); + } + service.node.addDependency(this.namespace); + } } export interface AliasedPortMutatingHookProps { diff --git a/src/service.ts b/src/service.ts index adf18275..b89dd8f0 100644 --- a/src/service.ts +++ b/src/service.ts @@ -394,5 +394,6 @@ export class Service extends Construct { this.ecsService.enableServiceConnect({ namespace: this.environment.cluster.defaultCloudMapNamespace.namespaceName, }); + this.ecsService.node.addDependency(this.environment.cluster.defaultCloudMapNamespace); } } diff --git a/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json b/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json index 9fb3a734..36e52720 100644 --- a/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json +++ b/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { "version": "21.0.0", "files": { - "1904e1ff90c4f297a8a8c9f4f5573101aa4cb632abb96486f141dc588c222614": { + "4ac410b83bf75ad3eee119980f62663b332db0d347a80e1c7a1493bf14772c05": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "1904e1ff90c4f297a8a8c9f4f5573101aa4cb632abb96486f141dc588c222614.json", + "objectKey": "4ac410b83bf75ad3eee119980f62663b332db0d347a80e1c7a1493bf14772c05.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json b/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json index 8563f25f..63902112 100644 --- a/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json +++ b/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json @@ -521,7 +521,10 @@ "TaskDefinition": { "Ref": "ServiceConnecttaskdefinitionB19E0536" } - } + }, + "DependsOn": [ + "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D" + ] }, "ServiceConnectserviceSecurityGroup0D1FCAE3": { "Type": "AWS::EC2::SecurityGroup", @@ -537,7 +540,143 @@ "VpcId": { "Ref": "productionenvironmentvpcAEB47DF7" } + }, + "DependsOn": [ + "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D" + ] + }, + "ClientServicetaskdefinitionTaskRoleACC19FE3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ClientServicetaskdefinition89718CF4": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Cpu": 256, + "Environment": [ + { + "Name": "PORT", + "Value": "80" + }, + { + "Name": "URL", + "Value": "http://name" + } + ], + "Essential": true, + "Image": "nathanpeck/greeter", + "Memory": 512, + "Name": "app", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [ + { + "HardLimit": 1024000, + "Name": "nofile", + "SoftLimit": 1024000 + } + ] + } + ], + "Cpu": "256", + "Family": "awsecsintegClientServicetaskdefinition11AA48A8", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "EC2", + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "ClientServicetaskdefinitionTaskRoleACC19FE3", + "Arn" + ] + } } + }, + "ClientServiceserviceService8F3E675C": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "productionenvironmentclusterC6599D2D" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 100 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClientServiceserviceSecurityGroupFBB92787", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "productionenvironmentvpcPrivateSubnet1Subnet53F632E6" + }, + { + "Ref": "productionenvironmentvpcPrivateSubnet2Subnet756FB93C" + } + ] + } + }, + "ServiceConnectConfiguration": { + "Enabled": true, + "Namespace": "production" + }, + "TaskDefinition": { + "Ref": "ClientServicetaskdefinition89718CF4" + } + }, + "DependsOn": [ + "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D" + ] + }, + "ClientServiceserviceSecurityGroupFBB92787": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/ClientService-service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "productionenvironmentvpcAEB47DF7" + } + }, + "DependsOn": [ + "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D" + ] } }, "Parameters": { diff --git a/test/aliased-port.integ.ts b/test/aliased-port.integ.ts index 3a9b91b4..110ebd9f 100644 --- a/test/aliased-port.integ.ts +++ b/test/aliased-port.integ.ts @@ -28,7 +28,27 @@ aliasedPortServiceDescription.add(new AliasedPortExtension({ })); new Service(stack, 'ServiceConnect', { - environment: environment, + environment, serviceDescription: aliasedPortServiceDescription, desiredCount: 1, }); + +const otherDescription = new ServiceDescription(); + +otherDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/greeter'), + environment: { + PORT: '80', + URL: 'http://name', + }, +})); + +new Service(stack, 'ClientService', { + environment, + serviceDescription: otherDescription, + desiredCount: 1, + enableServiceConnect: true, +});