cdklabs / cdk-from-cfn

A cloudformation json -> cdk typescript transpiler.
Apache License 2.0
57 stars 19 forks source link

Named conditions fail to migrate #694

Open steven10172 opened 3 months ago

steven10172 commented 3 months ago

When attempting to migrate a CloudFormation template that contains a named condition it failed with an error.

CloudFormation:

Conditions:
  HasSecurityGroupIds:
    Fn::Not:
      - Fn::Equals:
        - ""
        - Fn::Join: ["", Ref: SecurityGroupIds]

  CloudAuthVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      SecurityGroupIds:
        Fn::If:
          - HasSecurityGroupIds
          - Ref: SecurityGroupIds
          - Ref: 'AWS::NoValue'
      ServiceName:
        Fn::FindInMap:
          - CloudAuthVpcEndpointServices
          - Ref: 'AWS::Region'
          - vpces
      SubnetIds:
        - Fn::ImportValue: PrivateSubnet01
        - Fn::ImportValue: PrivateSubnet02
        - Fn::ImportValue: PrivateSubnet03
      VpcEndpointType: Interface
      VpcId:
        Fn::ImportValue: VPC

Error:

CloudAuthInfrastructureStackStack could not be generated because Conditions.HasSecurityGroupIds: data did not match any variant of untagged enum Singleton at line 22 column 5
iph commented 1 month ago

The error is weird but shockingly isn't named conditions that is the problem. It seems that Fn::Equals in combination with Fn::Join is not a great combo.

I'm unsure why. As an example, I took your template and modified to remove the Fn::Join:

Conditions:
  HasSecurityGroupIds:
    Fn::Not:
      - Fn::Equals:
        - ""
        - Ref: AWS::Region
Resources:
  CloudAuthVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      SecurityGroupIds:
        Fn::If:
          - HasSecurityGroupIds
          - Ref: SecurityGroupIds
          - Ref: 'AWS::NoValue'
      ServiceName:
        Fn::FindInMap:
          - CloudAuthVpcEndpointServices
          - Ref: 'AWS::Region'
          - vpces
      SubnetIds:
        - Fn::ImportValue: PrivateSubnet01
        - Fn::ImportValue: PrivateSubnet02
        - Fn::ImportValue: PrivateSubnet03
      VpcEndpointType: Interface
      VpcId:
        Fn::ImportValue: VPC

and gets past the issue.

iph commented 1 month ago

Ahh, this is a classic case of Conditions are not the same as the full support of functions.

When I initially wrote the Conditions parser, I took the documentation quite literally: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#w41aac23c24c21c29

The topics quite literally show the only supported conditions are And, Equals, If, Not, Or. The FUNCTIONs supported specifically are for Fn::If (which allows sub, select, join etc.)

Is this a valid template? If so, it may make sense to just support all functions and let the world run wild here.