From b27d968574f178dc13cfa332a9c17cd85f76c147 Mon Sep 17 00:00:00 2001 From: Xia Zhao <78883180+xazhao@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:33:13 -0700 Subject: [PATCH] fix(ecs): fromServiceArnWithCluster not accepting value from SSM Parameter string (#30902) ### Issue # (if applicable) Closes #30798. ### Reason for this change `fromServiceArnWithCluster()` function can't handle token value correctly. ### Description of changes Replace ``` const resourceName = arn.resourceName; ``` With ``` Arn.extractResourceName() ``` because the function above has the ability to handle token values. ### Description of how you validated changes - Updated the unit test - Manually verified the ECS cluster resource was used in the code pipeline when using the SSM parameter. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-ecs/lib/base/base-service.ts | 24 ++++++++++++------- .../aws-ecs/test/base-service.test.ts | 7 +++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index 2cbea1c5eb0b4..89fc0d7434f41 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -19,6 +19,8 @@ import { ArnFormat, FeatureFlags, Token, + Arn, + Fn, } from '../../../core'; import * as cxapi from '../../../cx-api'; import { RegionInfo } from '../../../region-info'; @@ -516,16 +518,20 @@ export abstract class BaseService extends Resource public static fromServiceArnWithCluster(scope: Construct, id: string, serviceArn: string): IBaseService { const stack = Stack.of(scope); const arn = stack.splitArn(serviceArn, ArnFormat.SLASH_RESOURCE_NAME); - const resourceName = arn.resourceName; - if (!resourceName) { - throw new Error(`Missing resource Name from service ARN: ${serviceArn}`); - } - const resourceNameParts = resourceName.split('/'); - if (resourceNameParts.length !== 2) { - throw new Error(`resource name ${resourceName} from service ARN: ${serviceArn} is not using the ARN cluster format`); + const resourceName = Arn.extractResourceName(serviceArn, 'service'); + let clusterName: string; + let serviceName: string; + if (Token.isUnresolved(resourceName)) { + clusterName = Fn.select(0, Fn.split('/', resourceName)); + serviceName = Fn.select(1, Fn.split('/', resourceName)); + } else { + const resourceNameParts = resourceName.split('/'); + if (resourceNameParts.length !== 2) { + throw new Error(`resource name ${resourceName} from service ARN: ${serviceArn} is not using the ARN cluster format`); + } + clusterName = resourceNameParts[0]; + serviceName = resourceNameParts[1]; } - const clusterName = resourceNameParts[0]; - const serviceName = resourceNameParts[1]; const clusterArn = Stack.of(scope).formatArn({ partition: arn.partition, diff --git a/packages/aws-cdk-lib/aws-ecs/test/base-service.test.ts b/packages/aws-cdk-lib/aws-ecs/test/base-service.test.ts index d670e8fbc8c32..9ef3b54a68c43 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/base-service.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/base-service.test.ts @@ -38,7 +38,7 @@ describe('When import an ECS Service', () => { test('throws an expection if no resourceName provided on fromServiceArnWithCluster', () => { expect(() => { ecs.BaseService.fromServiceArnWithCluster(stack, 'Service', 'arn:aws:ecs:service-region:service-account:service'); - }).toThrowError(/Missing resource Name from service ARN/); + }).toThrowError(/Expected resource name in ARN, didn't find one: 'arn:aws:ecs:service-region:service-account:service'/); }); test('throws an expection if not using cluster arn format on fromServiceArnWithCluster', () => { @@ -47,6 +47,11 @@ describe('When import an ECS Service', () => { }).toThrowError(/is not using the ARN cluster format/); }); + test('skip validation for tokenized values', () => { + expect(() => ecs.BaseService.fromServiceArnWithCluster(stack, 'Service', + cdk.Lazy.string({ produce: () => 'arn:aws:ecs:service-region:service-account:service' }))).not.toThrow(); + }); + test('should add a dependency on task role', () => { // GIVEN const vpc = new ec2.Vpc(stack, 'Vpc');