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.35k stars 3.76k forks source link

cdk migrate: Cloudformation conditions are tagged enums. #29181

Open v4de opened 4 months ago

v4de commented 4 months ago

Describe the bug

I am trying to convert our cloudformation templates to cdk by using the new experimental cdk migrate. I have run into an issue when referencing one of our templates and expect others to be the same. I have attached the template ecs.service.template in the reproduction steps and provided some additional context on how it is used.

Expected Behavior

I expect a cdk project to be created and conditions to be created based on !and, !equals, !not, !or, etc. I also expected a way to pass parameters via the context, and for references to the stack parameters to use get.context.

Current Behavior

When running cdk migrate I run into this error that I can not seem to find any information about.

cdk migrate --stack-name ecs-service --language typescript --from-path ecs.service.template
This command is an experimental feature.
 ❌  Migrate failed for `ecs-service`: stack generation failed due to error 'Conditions.cCapacityProviderCompute[1][0]: untagged and internally tagged enums do not support enum input at line 334 column 14'

stack generation failed due to error 'Conditions.cCapacityProviderCompute[1][0]: untagged and internally tagged enums do not support enum input at line 334 column 14'

Reproduction Steps

  1. Create a local copy of file in directory of your choice: ecs.service.template.txt
  2. Remove .txt
  3. From directory with the template file run cdk migrate --stack-name ecs-service --language typescript --from-path ecs.service.template

Possible Solution

No response

Additional Information/Context

At my company we create one cloudformation template and then reuse the same template and pass a ecs.service.parameters json file that we populate during our deployment process in our CD tool (Azure DevOps). So we only use one template file that is reused in many pipelines to create different resources and different conditions are used to enable/disable certain configurations. One of the main benefits of moving to CDK for us is the ability to pass a list of containers for ECS from the pipeline, without having to maintain multiple template files.

CDK CLI Version

2.128.0 (build d995261)

Framework Version

No response

Node.js Version

v20.10.0

OS

Windows 10 Enterprise 10.0.19044

Language

TypeScript

Language Version

No response

Other information

No response

TheRealAmazonKendra commented 4 months ago

For the parameters, we populate those in the app file using props, not parameters, but I certainly can see a use case here for providing a separate parameter file and/or parameter list. I am going to add that to our list of features to add.

As for the error you're getting, I'm a little stumped. I'll investigate this further.

xavadu commented 4 months ago

We are having the same error message when using Pseudo parameters reference

Here the template example:

  GetSingleAnimalLambda:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        - !Sub
          - arn:aws:iam::${Account}:policy/LogExtensionPolicy
          - { Account: !Ref AWS::AccountId }

Our use case is to use the same template on separate AWS Environment (dev, stage, and prod)

Update Replacing the !Sub as this makes the trick

- !Sub arn:aws:iam::${AWS::AccountId}:policy/LogExtensionPolicy

Update 2 but in other situation, not sure if it is possible to go through it, per example:

          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: 'sts:AssumeRole'
                Resource: !Sub
                  - 'arn:aws:iam::${Account}:role/mccsIot'
                  - { Account: !FindInMap ['MCCSAccount', !Ref Env, 'Number'] }

this throws the same error, Is there a possible workaround for this?

TheRealAmazonKendra commented 3 months ago

Oh, great, I think I understand the issue now. Thank you for the extra context. I will try to get this fix in before our next release. I'll update here if I'm not able to.

TheRealAmazonKendra commented 3 months ago

Using the samples below, I'm unable to reproduce the error so I'm wondering if this issue was partially fixed by some of the other work already done. If you upgrade to v2.132, do you still see the same error for pseudo parameter references?

We are having the same error message when using Pseudo parameters reference

Here the template example:

  GetSingleAnimalLambda:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        - !Sub
          - arn:aws:iam::${Account}:policy/LogExtensionPolicy
          - { Account: !Ref AWS::AccountId }

Our use case is to use the same template on separate AWS Environment (dev, stage, and prod)

Update Replacing the !Sub as this makes the trick

- !Sub arn:aws:iam::${AWS::AccountId}:policy/LogExtensionPolicy

Update 2 but in other situation, not sure if it is possible to go through it, per example:

          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: 'sts:AssumeRole'
                Resource: !Sub
                  - 'arn:aws:iam::${Account}:role/mccsIot'
                  - { Account: !FindInMap ['MCCSAccount', !Ref Env, 'Number'] }

this throws the same error, Is there a possible workaround for this?

xavadu commented 3 months ago

Here is a full template example that fails

root.yml

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Stage:
    Type: String
  StackName:
    Type: String
  StackCreationTime:
    Type: String
  BucketFolder:
    Type: String

Resources:
  APP:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub
        - https://s3-eu-west-1.amazonaws.com/my-bucket-${FOLDER}/packaged-app.yml
        - { FOLDER: !Ref BucketFolder }
      Parameters:
        Stage: !Ref Stage
        BucketFolder: !Ref BucketFolder
      TimeoutInMinutes: 5

cdk migrate throw this error

$ cdk migrate --stack-name "xxxx" --language typescript --from-path "./root.yml"

 ❌  Migrate failed for `xxxx`: XxxxStack could not be generated because Resources.APP.Properties.TemplateURL[1].FOLDER: untagged and internally tagged enums do not support enum input at line 20 column 21

XxxxDevStack could not be generated because Resources.APP.Properties.TemplateURL[1].FOLDER: untagged and internally tagged enums do not support enum input at line 20 column 21

after change !Sub for Fn::Sub like that

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Stage:
    Type: String
  StackName:
    Type: String
  StackCreationTime:
    Type: String
  BucketFolder:
    Type: String

Resources:
  APP:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: Fn::Sub
        - https://s3-eu-west-1.amazonaws.com/my-bucket-${FOLDER}/packaged-app.yml
        - { FOLDER: !Ref BucketFolder }
      Parameters:
        Stage: !Ref Stage
        BucketFolder: !Ref BucketFolder
      TimeoutInMinutes: 5

The error for the same command changed to

 ❌  Migrate failed for `asm-registry-dev`: Nested mappings are not allowed in compact mappings

Nested mappings are not allowed in compact mappings

But, after change Fn::Sub with Fn::Join it works just fine

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Stage:
    Type: String
  StackName:
    Type: String
  StackCreationTime:
    Type: String
  BucketFolder:
    Type: String

Resources:
  APP:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: Fn::Join
        - ''
        - - 'https://s3-eu-west-1.amazonaws.com/my-bucket-'
        - !Ref BucketFolder
        - '/packaged-app.yml'
      Parameters:
        Stage: !Ref Stage
        BucketFolder: !Ref BucketFolder
      TimeoutInMinutes: 5

I using the last cdk version

$ cdk --version
2.132.1 (build 9df7dd3)
AELIENUS commented 3 months ago

I have the same issue. Here is a minimal version of my template:

Parameters:
  Environment: { Type: String, Default: "dev" }
  BaseName: { Type: String, Default: "product" }

Resources:
  TestLambda:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.12
      Handler: index.lambda_handler
      FunctionName: TestFunc
      Code:
        ZipFile: 
          Fn::Sub: 
            - | 
              import json
              import boto3
              import botocore.exceptions
              import os
              import cfnresponse
              import logging

              # Configure Logging
              logger = logging.getLogger()
              logger.setLevel(logging.INFO)
              globalEvent = None

              def lambda_handler(event, context):
                globalEvent = event
                logger.info("Generating appsettings.json")
                logger.info(json.dumps(event))

                environ = "${EnvironmentIdentifier}"

                print(environ)
            - EnvironmentIdentifier: !Join [ "-", [ !Ref BaseName, !Ref Environment ] ]

I get the error:

 ❌  Migrate failed for `repro`: ReproStack could not be generated because Resources.TestLambda.Properties.Code.ZipFile.Fn::Sub[1].EnvironmentIdentifier: untagged and internally tagged enums do not support enum input at line 37 column 38

ReproStack could not be generated because Resources.TestLambda.Properties.Code.ZipFile.Fn::Sub[1].EnvironmentIdentifier: untagged and internally tagged enums do not support enum input at line 37 column 38

I am using version 2.133.0 of CDK

steffakasid commented 3 weeks ago

I've got the same issue with the following condition:

Conditions:
  UseDbSnapshot: !Not [!Equals [!Ref SnapshotIdentifier, ""]]

Where SnapshotIdentifier is just a 'string' parameter.

Regards Steffen

steffakasid commented 3 weeks ago

As a workaround: Convert the YAML definition to JSON using the Application Composer and run the migrate on the JSON worked fine for me.

anathema-one commented 1 week ago

As a work around, I used https://github.com/aws-cloudformation/rain

rain fmt cloudformation.yaml -j > cloudformation.json

and then used.

cdk migrate --language typescript --from-path cloudformation.json

And it worked just fine, however this is still a work around, and would love for this to get fixed natively. Thanks!