-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
No longer accessing another stack's resource causes deadly embrace #7602
Comments
I have a bit more code to support this as you create a circular reference that ends up meaning NO changes can be made without deleting an entire stack export class StackA extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
new Instance(this, "instance1", {
allowAllOutbound: true,
machineImage: MachineImage.genericLinux({
"us-east-2": "ami-*****",
}),
blockDevices: [
{ deviceName: "/dev/sda1", volume: mainVolume },
{ deviceName: "/dev/sdm", volume: largeVolume },
],
vpc,
instanceType: InstanceType.of(InstanceClass.M5A, InstanceSize.XLARGE2),
});
new IamStack(this, "IAM stack", {
instances: [instance],
env: props?.env,
});
}
}
interface IamStackProps extends StackProps {
instances: IInstance[];
}
export class IamStack extends Stack {
constructor(scope: Construct, id: string, props: IamStackProps) {
// ...
this.group.addToPolicy(
new PolicyStatement({
actions: ["ec2-instance-connect:SendSSHPublicKey"],
effect: Effect.ALLOW,
resources: props.instances.map(this.buildArn),
})
);
// ...
}
private buildArn(instance: IInstance): string {
return `arn:${Aws.PARTITION}:ec2:${Aws.REGION}:${Aws.ACCOUNT_ID}:instance/${instance.instanceId}`;
}
} No change can be made to the instance resource that would require it to recreate (update the AMI). And no change can be made to the Policy statement (including deleting it). The error is The only want to solve this problem is to delete the dependent stack. Deploy the parent stack. Add back the dependent stack. |
so I found a way around this. If you are updating the child stack you can deploy with the If you are changing the parent stack it's a 2 step process.
|
We are aware of this issue (duplicate #3414), but I am not sure exactly what we can do about it. Any ideas? |
Our solution is to deploy the substack with the Even some documentation around that would be stronger than just two immutable stacks. Could you always update leaf nodes first, then update the full stack again |
@eladb We hit this problem again today. After thinking through it again, we are wondering... could you mark the no longer referenced output for deletion, but not actually delete it in this pass. Then in a subsequent deploy, it could be safely deleted? |
The CDK (currently) doesn't have knowledge of the current state, only the desired state. The exports/imports that are created as a result of cross stack references are only defined if the reference exists. Otherwise they are simply not defined in your CDK app and we don't know that they existed there before. |
Could we force the export somehow, even without the resource? If I understand correctly the export name is only based on the path of the construct and the type of reference we're using, not the actual construct itself (please correct me if I'm wrong). Could we have an helper method that will generate the export name for us, so that we can manually keep the export while removing the resource?
The method would generate the name If we need to keep the value untouched (instead of hardcoding 'dummy_value' here), could we use AwsCustomResource to query the existing value of this export and return it as part of the helper method as well? I personally have to add those exports manually when I am in this situation (hardcoded in the code), and I have a helper script to help query the names from CloudFormation for all stacks. But a dynamic way of generating them would go a long way. |
We encountered this unsolvable case in a trivial infrastructure: RDS stack -> (referenced in) -> ECS stack This causes CDK to create CloudFormation outputs and inputs between the two stacks, which is fine. However, at some point, we decided to drop this dependency in favor of another approach of retrieving Database credentials (using Secrets Manager, etc). This caused CDK to fail though because it first detects that the RDS stack has no longer any dependencies and tries to delete the exported output, but at the same time - fails to do so - because the ECS stack is currently using that output (even though our desired effect is that it no longer uses it. Is there an elegant solution to this? Maybe one where CDK is smart enough to first deploy the ECS stack to clean up the link between the two? |
@Dzhuneyt while dealing with removing cross-stack references can be tricky in the CDK, there is actually a way to do it. Check out this article: https://www.endoflineblog.com/cdk-tips-03-how-to-unblock-cross-stack-references for a step-by-step guide on how to unblock yourself. Thanks, |
I have a workaround here too: #5819 (comment) |
@skinny85, Thank you for your post. Do you happen to have an example of creating the dummy resource in the case one’s stack is in a CDK pipeline? |
It's exactly the same. You just |
Coming up with all the values to create the dummies for the various stages the stack appears in is not exactly the same from my perspective. But think I've dug deep enough to create a function that'll compute them... what @smeyffret was suggesting. Seems like that would be a low hanging fruit option to offer up to help people navigate this deadly embrace while something more magical is worked out. @eladb @rix0rrr has the explicitly declare the output option been considered -- from above: #7602 (comment) |
"Deadly embrace" is a great term but an annoying problem. The best way to work around it is to manually ensure the CloudFormation Export exists while you remove the consuming relationship. Adam has a blog post about this, but the mechanism can be more smooth. Add a method, `stack.exportAttribute(...)` which can be used to create the Export for the duration of the deployment that breaks the relationship, and add an explanation of how to use it. Fixes #7602.
…e" (#12778) Deadly embrace (<3 who came up with this term) is an issue where a consumer stack depends on a producer stack via CloudFormation Exports, and you want to remove the use from the consumer. Removal of the resource sharing implicitly removes the CloudFormation Export, but now CloudFormation won't let you deploy that because the deployment order is always forced to be (1st) producer (2nd) consumer, and when the producer deploys and tries to remove the Export, the consumer is still using it. The best way to work around it is to manually ensure the CloudFormation Export exists while you remove the consuming relationship. @skinny85 has a [blog post] about this, but the mechanism can be more smooth. Add a method, `stack.exportValue(...)` which can be used to create the Export for the duration of the deployment that breaks the relationship, and add an explanation of how to use it. Genericize the method a bit so it also solves a long-standing issue about no L2 support for exports. Fixes #7602, fixes #2036. [blog post]: https://www.endoflineblog.com/cdk-tips-03-how-to-unblock-cross-stack-references ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
|
…e" (aws#12778) Deadly embrace (<3 who came up with this term) is an issue where a consumer stack depends on a producer stack via CloudFormation Exports, and you want to remove the use from the consumer. Removal of the resource sharing implicitly removes the CloudFormation Export, but now CloudFormation won't let you deploy that because the deployment order is always forced to be (1st) producer (2nd) consumer, and when the producer deploys and tries to remove the Export, the consumer is still using it. The best way to work around it is to manually ensure the CloudFormation Export exists while you remove the consuming relationship. @skinny85 has a [blog post] about this, but the mechanism can be more smooth. Add a method, `stack.exportValue(...)` which can be used to create the Export for the duration of the deployment that breaks the relationship, and add an explanation of how to use it. Genericize the method a bit so it also solves a long-standing issue about no L2 support for exports. Fixes aws#7602, fixes aws#2036. [blog post]: https://www.endoflineblog.com/cdk-tips-03-how-to-unblock-cross-stack-references ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
CDK's automatic determination and synthesis of exports to imports can get locked into a deadly embrace that cannot be resolved without destroying your stacks.
Reproduction Steps
Stack1 creates a common Security Group, sg1.
Stack2 uses sg1.
CDK's automatic determination and synthesis described here, will generate an export output from Stack1 for sg1 and an Fn:ImportValue into Stack2.
Then you deploy these stacks.
Later, you decide that Stack2 really needs it's own more specific Security Group, so you create it's own sg2. Again, CDK's automatic determination and synthesis realizes that sg1 is no longer referenced by Stack2 (or any other stack) and attempts to delete the Export of sg1 from Stack1.
This will fail and cannot be deployed.
CloudFormation will be prevented from deleting sg1 as an export from Stack1 since it is currently being used as an Import in the (existing) Stack2. Ironically, you were trying to update Stack2 to no longer reference Stack1's sg1.
Error Log
Environment
Other
This is 🐛 Bug Report
The text was updated successfully, but these errors were encountered: