aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.47k stars 3.83k forks source link

ecs.FargateService: from_service_arn_with_cluster not accepting value from SSM Parameter string #30798

Closed tisauro closed 1 month ago

tisauro commented 1 month ago

Describe the bug

When retrieving a Fargate service arn from the parameter store and passing it to the function from_service_arn_with_cluster it throws the runtime exception: RuntimeError: Error: resource name ${Token[TOKEN.236]} from service ARN: ${Token[TOKEN.226]} is not using the ARN cluster format

Expected Behavior

accept the format

Current Behavior

raises exception RuntimeError: Error: resource name ${Token[TOKEN.236]} from service ARN: ${Token[TOKEN.226]} is not using the ARN cluster format

Reproduction Steps

class TestIacStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # The code that defines your stack goes here

        alb_ecs_service = ecs_patterns.ApplicationLoadBalancedFargateService(self, 'Service',
                                                                             cluster=ecs.Cluster(self,
                                                                                                 'my_cluster',
                                                                                                 cluster_name="TestCluster"
                                                                                                 ),
                                                                             memory_limit_mib=512,
                                                                             cpu=0.5,
                                                                             task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
                                                                                 image=ecs.ContainerImage.from_registry(
                                                                                     "amazon/amazon-ecs-sample")),
                                                                             public_load_balancer=True,
                                                                             desired_count=1,
                                                                             )

        ssm.StringParameter(self, "ssm_param",
                            parameter_name="ServiceArn",
                            string_value=alb_ecs_service.service.service_arn,
                            )

        ecs_service_arn = ssm.StringParameter.value_for_string_parameter(
            self,
            parameter_name="ServiceArn",
        )
        ecs_service = ecs.FargateService.from_service_arn_with_cluster(self, "FargateServiceArn",
                                                                       service_arn=ecs_service_arn)

        deploy_action = pipelineactions.EcsDeployAction(
            action_name="DeployToStage",
            service=ecs_service,
            image_file=codepipeline.ArtifactPath(codepipeline.Artifact("BuildArtifact"), 'imagedefinitions.json'),
            # deployment_timeout=Duration.minutes(60),
        )

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.148.0 (build e5740c0)

Framework Version

No response

Node.js Version

v18.19.1

OS

Linux

Language

Python

Language Version

3.9.19

Other information

I am trying to retrieve the ecs service from arn in a different module for passing it to a pipeline action as shown in the example above

ashishdhingra commented 1 month ago

Hi @tisauro,

Good morning. Thanks for opening the issue.

Although the issue is reproducible using following TypeScript CDK code:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as pipelineActions from 'aws-cdk-lib/aws-codepipeline-actions'

export class TypescriptStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const albEcsService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'Service', {
      cluster: new ecs.Cluster(this, 'TestCluster', {
        clusterName: 'TestCluster'
      }),
      memoryLimitMiB: 512,
      cpu: 0.5,
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample')
      },
      publicLoadBalancer: true,
      desiredCount: 1
    });

    new ssm.StringParameter(this, 'ssmParam', {
      parameterName: 'ServiceArn',
      stringValue: albEcsService.service.serviceArn
    });

    const ecsServiceArn = ssm.StringParameter.valueForStringParameter(this, 'ServiceArn');
    const ecsService = ecs.FargateService.fromServiceArnWithCluster(this, 'FargateServiceArn', ecsServiceArn);
    const deployAction = new pipelineActions.EcsDeployAction({
      actionName: 'DeployToStage',
      service: ecsService,
      imageFile: new codepipeline.ArtifactPath(new codepipeline.Artifact('BuildArtifact'), 'imagedefinitions.json')
    });
  }
}

which gives below error:

Error: resource name ${Token[TOKEN.246]} from service ARN: ${Token[TOKEN.236]} is not using the ARN cluster format
    at Function.fromServiceArnWithCluster (/Users/<<REDACTED>>/dev/repros/cdk/issue30798/typescript/node_modules/aws-cdk-lib/aws-ecs/lib/base/base-service.js:1:3823)
    at new TypescriptStack (/Users/<<REDACTED>>/dev/repros/cdk/issue30798/typescript/lib/typescript-stack.ts:32:43)
    at Object.<anonymous> (/Users/<<REDACTED>>/dev/repros/cdk/issue30798/typescript/bin/typescript.ts:7:1)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module.m._compile (/Users/<<REDACTED>>/dev/repros/cdk/issue30798/typescript/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/<<REDACTED>>/dev/repros/cdk/issue30798/typescript/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)

The reason we are getting the error is because:

For values which are resolved later during deployment, it appears that these cannot be used as such in static helper method BaseService.fromServiceArnWithCluster().

Thanks, Ashish

pahud commented 1 month ago

Yes fromServiceArnWithCluster() does not handle the serviceArn correctly when it is a Token.

https://github.com/aws/aws-cdk/blob/727e886805da021c2373e74754fd2d7492a8aac6/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts#L516-L537

The bug is at

https://github.com/aws/aws-cdk/blob/727e886805da021c2373e74754fd2d7492a8aac6/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts#L519

We should use Arn.extractResourceName() instead, which handles it well with Token support. See more samples here.

Making this a p1 bug and we welcome pull requests.

github-actions[bot] commented 1 month ago

Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] commented 1 month ago

Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

aws-cdk-automation commented 1 month ago

Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one.