core: Double nested stack outputs not resolved correctly
See original GitHub issueWhen multiple stacks are nested inside of each other, accessing resources that depend on parameters doesn’t seem to work correctly. I don’t have a good explanation of what is happening, but I have multiple ways to fix whatever the problem is.
The CloudFormation I’m trying to import that is failing looks like:
root-stack.yaml
|----------load-balancers.yaml
|----------load-balancer-stack-1.yaml
|----------load-balancer-stack-2.yaml
|----------load-balancer-stack-3.yaml
The problem we’re running into is using the TargetGroup
from load-balancer-stack-1.yaml
in some new CDK resources.
This is related to https://github.com/aws/aws-cdk/issues/1374
Reproduction Steps
bin/cdk-test.ts
:
#!/usr/bin/env node
import { App, Stack } from '@aws-cdk/core';
import { CfnInclude } from '@aws-cdk/cloudformation-include';
import { CfnBucket, Bucket } from '@aws-cdk/aws-s3';
class DoubleNestedStack extends Stack {
readonly outputBucketName : CfnBucket;
constructor(scope: App, id: string) {
super(scope, id);
const parentTemplate = new CfnInclude(this, 'ParentStack', {
templateFile: 'parent-stack.yaml',
});
const middleTemplate = parentTemplate.loadNestedStack('MiddleStack', {
templateFile: 'middle-stack.yaml'
}).includedTemplate;
const bottomTemplate = middleTemplate.loadNestedStack('BottomStack', {
templateFile: 'bottom-stack.yaml'
}).includedTemplate;
this.outputBucketName = bottomTemplate.getResource('Bucket') as CfnBucket;
}
}
class OtherStack extends Stack {
constructor(scope: App, id: string, bucketName: string) {
super(scope, id);
const newBucket = new Bucket(this, 'newBucket', {
bucketName: bucketName
});
}
}
const app = new App();
const doubleNestedStack = new DoubleNestedStack(app, 'DoubleNestedStack');
const bucketName = doubleNestedStack.outputBucketName.bucketName as string;
new OtherStack(app, 'OtherStack', bucketName);
parent-stack.yaml
:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MiddleStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: 'https://s3.amazonaws.com/this-doesnt-matter.yaml'
middle-stack.yaml
:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
BottomStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: 'https://s3.amazonaws.com/this-doesnt-matter.yaml'
Parameters:
Name: anything
bottom-stack.yaml
:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
Name:
Type: String
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref Name
What did you expect to happen?
I expected cdk synth
to work and my OtherStack
to be able to reference the double nested stack’s resource. (I realize that I’m trying to name an S3 bucket the same thing as another bucket, but that’s not the problem)
[masonme@f45c89b36d13] $ cdk synth
Successfully synthesized to /Users/masonme/cdk-migration-test/cdk.out
Supply a stack id (DoubleNestedStack, OtherStack) to display its template.
What actually happened?
Failure Output:
[masonme@f45c89b36d13] $ cdk synth
/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/construct-compat.ts:83
^
Error: Cannot use tokens in construct ID: DoubleNestedStackParentStackMiddleStackBottomStackNestedStackBottomStackNestedStackResource43C48F46Outputs.${Token[DoubleNestedStack.ParentStack.MiddleStack.Middl...arentStackMiddleStackBottomStackName8BE86CBFRef.LogicalID.48]}
at new Construct (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/construct-compat.ts:83:13)
at new CfnElement (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/cfn-element.ts:57:5)
at new CfnOutput (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/cfn-output.ts:50:5)
at createNestedStackOutput (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/refs.ts:207:14)
at resolveValue (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/refs.ts:86:25)
at resolveValue (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/refs.ts:87:12)
at Object.resolveReferences (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/refs.ts:30:24)
at Object.prepareApp (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/prepare-app.ts:31:3)
at Object.synthesize (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/private/synthesis.ts:24:3)
at App.synth (/Users/masonme/cdk-migration-test/node_modules/@aws-cdk/core/lib/stage.ts:180:23)
Subprocess exited with error 1
cdk synth
failed due to CDK using a token in the ID of an internal construct. The code for this ID seems to be here: https://github.com/aws/aws-cdk/blob/7966f8d48c4bff26beb22856d289f9d0c7e7081d/packages/%40aws-cdk/core/lib/private/refs.ts#L204
I’ve found multiple ways to avoid the problem:
- Change
bottom-stack.yaml
’sBucketName
property to a string instead of a reference to a parameter - Remove
OtherStack
or its usage ofBottomStack
’s output
Environment
- CDK CLI Version : 1.103.0 (build bc13a66)
- Framework Version: 1.103.0
- Node.js Version: v14.15.4
- OS : OS X 10.14.6 (18G9216)
- Language (Version): TypeScript (Version 4.1.5)
Other
This is 🐛 Bug Report
Issue Analytics
- State:
- Created 2 years ago
- Comments:8 (6 by maintainers)
Top GitHub Comments
I’ll take a look next week
⚠️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.