Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(CDK): Export changes prevent stack updates #17741

Closed
apmclean opened this issue Nov 29, 2021 · 5 comments
Closed

(CDK): Export changes prevent stack updates #17741

apmclean opened this issue Nov 29, 2021 · 5 comments
Assignees
Labels
bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. package/tools Related to AWS CDK Tools or CLI response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@apmclean
Copy link

What is the problem?

While creating a multi-stack app I am referring to resources between stacks. The CDK does a great job understanding those relationship automatically and creating an export for me.

However when a change is made in a stack that consumes resources where those resources are no longer used (in my case setting/updating Transit Gateway Routes) which have a level of dynamism based on routing traffic for inspection etc the CDK insists on deleting previous used (but now not) exports in the underlying stack.

This is blocked by CloudFormation which prevents the deletion of the stack. The 'stack above' cannot be updated because the 'stack below' doesn't export the resources it needs for the update. Both stacks are effectively 'locked' from updates.

Reproduction Steps

Deploy the following with a cdk deploy --all:

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import * as ec2 from '@aws-cdk/aws-ec2'

const app = new cdk.App();

// Transit Gateway Stack
class TransitGateway extends cdk.Stack {
    transitGateway: ec2.CfnTransitGateway

    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        this.transitGateway = new ec2.CfnTransitGateway(this, "TransitGateway", {})
    }
}
const transitGatewayStack = new TransitGateway(app, 'TransitGateway', {});

// 'n' number of VPCs That will eventually use the TGW
class Vpc extends cdk.Stack {
    vpc: ec2.Vpc

    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        this.vpc = new ec2.Vpc(this, "Vpc", {
            cidr: "10.1.0.0/16",
            subnetConfiguration: [
                {
                    name: "Public",
                    cidrMask: 24,
                    subnetType: ec2.SubnetType.PUBLIC
                },
                {
                    name: "Private",
                    cidrMask: 24,
                    subnetType: ec2.SubnetType.PRIVATE_WITH_NAT
                },
                {
                    name: "TransitGateway",
                    cidrMask: 28,
                    subnetType: ec2.SubnetType.PRIVATE_ISOLATED
                }
            ]
        })
    }
}
const vpcStack = new Vpc(app, "Vpc", {})
// I'm deploying many more VPCs in this stage, along with firewalls, gateway load balancers etc

// Finally have a stack that wires them all together via the TGW
class TransitRoutes extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        const association = new ec2.CfnTransitGatewayVpcAttachment(this, "VpcAttach", {
            transitGatewayId: transitGatewayStack.transitGateway.attrId,
            subnetIds: vpcStack.vpc.selectSubnets({subnetGroupName: "TransitGateway"}).subnetIds,
            vpcId: vpcStack.vpc.vpcId
        })
        vpcStack.vpc.selectSubnets({subnetGroupName: "Public"}).subnets.forEach((subnet, index) => {
            const route = new ec2.CfnRoute(this, `RouteToTGW${index}`, {
                routeTableId: (subnet as ec2.Subnet).routeTable.routeTableId,
                destinationCidrBlock: "10.100.2.0/24",
                transitGatewayId: transitGatewayStack.transitGateway.attrId
            })
            route.node.addDependency(association)
        })
    }
}

const transitRoutesStack = new TransitRoutes(app, "TransitRoutes", {})

After it has deployed successfully. Change line 59 to be Private instead of Public. ie:

vpcStack.vpc.selectSubnets({subnetGroupName: "Private"}).subnets.forEach((subnet, index) => {

Attempt to deploy changes. CDK will attempt to delete the RouteTableID exports for the public subnets in the Vpc Stack. This will be prevented because the TransitGateway Stack depends on them. Neither stack can be updated at this point.

What did you expect to happen?

The CDK would understand a previously used export was possibly / probably still in use and preserve it. I don't see a lot of value in deleting an existing export? Where an export has been created, I'd expect it to exist for the life-cycle of the stack.

Where that's not possible some kind of 'exportAll()' method on a construct would come in handy!

What actually happened?

CDK insists on deleting the now unused export which locks both stacks up preventing either from being updated.

CDK CLI Version

1.134.0 (build dd5e12d)

Framework Version

No response

Node.js Version

v14.18.1

OS

OSX 11.6.1

Language

Typescript

Language Version

3.9.10

Other information

No response

@apmclean apmclean added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 29, 2021
@github-actions github-actions bot added the @aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud label Nov 29, 2021
@skinny85
Copy link
Contributor

skinny85 commented Nov 29, 2021

Hey @apmclean,

thanks for opening the issue. This is a known problem with the CDK. This blog post explains how to unblock yourself in this situation.

We have plans for solving this in the future permanently (for example, aws/aws-cdk-rfcs#309), but for now, you'll have to unblock yourself "manually".

Thanks,
Adam

@skinny85 skinny85 added package/tools Related to AWS CDK Tools or CLI response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed @aws-cdk/aws-ec2 Related to Amazon Elastic Compute Cloud labels Nov 29, 2021
@skinny85 skinny85 assigned rix0rrr and unassigned njlynch Nov 29, 2021
@apmclean
Copy link
Author

Thanks for the details, I also found this buried at the bottom of the official AWS documentation in a round-about way for those who venture far enough into the bottom of the documentation.

Is there any way to know the name that the CDK will create for an export in advance? ie: can I proactively include an Export() for any resource I might need to consume in the above layers but use the same name that the above layers would expect if they were synthed without my using Export() - ie: in consuming stacks I don't need to do my own fn::Imports.

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 29, 2021
@skinny85
Copy link
Contributor

There's no way to know the name in advance, but you can call the Stack.exportValue() method if you want, like described in the blog post.

@skinny85 skinny85 added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 29, 2021
@apmclean
Copy link
Author

Alright, I think if I'm going to put the effort into naming exports and managing all that between stacks, I'll just switch to using SSM parameters. Looser coupling. Thanks!

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. package/tools Related to AWS CDK Tools or CLI response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
Development

No branches or pull requests

4 participants