Search code examples
aws-cdkaws-cdk-typescript

CDK update from version 1 to version 2 breaks the subnets setup already deployed


I've been using CDK for some long time, and I'm upgrading all my stacks from version 1 to version 2

I have base stacks with network, subnets, etc. and then on top of that, I have other stacks with different resources, rds, ec2, ecs, etc.

On CDK 1, the cloudformation template generated with CDK was:

        "AvailabilityZone": {
          "Fn::Select": [
            0,
            {
              "Fn::GetAZs": ""
            }
          ]
        },

On CDK2, it changed to:

"AvailabilityZone": "us-east-1a",

on the cdk diff the change is easily visible:

[~] AWS::EC2::Subnet RodAccountDBVPC/RodSubnet1/Subnet 
MySubnetAAAAA02A replace
 └─ [~] AvailabilityZone (requires replacement)
     └─ @@ -1,8 +1,1 @@
        [-] {
        [-]   "Fn::Select": [
        [-]     0,
        [-]     {
        [-]       "Fn::GetAZs": ""
        [-]     }
        [-]   ]
        [-] }
        [+] "us-east-1a"

and on deploy it fails, because it is trying to replace the already existant Subnets that already have a lot of resources on them:

10:38:55 PM | CREATE_FAILED        | AWS::EC2::Subnet                      | RodAccount...net3SubnetBBBBBBBB
Resource handler returned message: "The CIDR '172.10.16.0/26' conflicts with another subnet (Service: Ec2, Status Code: 400, Request ID: 2caaaa4e-a141-43f0-bb18-aaab745872d5)"
(RequestToken: 9baaaaa0-9488-2cd7-6ed0-aaa521b8417c, HandlerErrorCode: AlreadyExists)

so the question is, on CDK 2, is there a way I can set the availability zone to use a cloudformation Fn::Select function, instead of the hardcoded string zone that it is trying to set now?

the code where I defined the VPC:

    const vpc = new ec2.Vpc(this, 'RodAccountDBVPC', {
      ipAddresses: ec2.IpAddresses.cidr(this.config['172.10.0.0/20']),
      subnetConfiguration: [
        {
          cidrMask: 26,
          name: 'RDS',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
        {
          cidrMask: 26,
          name: 'PublicNetwork',
          subnetType: ec2.SubnetType.PUBLIC,
        }
      ],
      natGateways: 1,
    });

Solution

  • We had the same issue during our upgrade from CDKv1 to CDKv2. The stack was initially created without a specific region and the region was later added, but the stack was never deployed since then.

    You'll probably see something like this after running cdk diff:

    Conditions
    [-] Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}
    

    You need to remove the hardcoded region from the env in your bin/stack.ts file

    env: { account: "1234567890", region: "eu-central-1" }
    

    Thanks to gshpychka and a colleague who pointed me in the right direction.

    https://docs.aws.amazon.com/cdk/v2/guide/environments.html