-
Notifications
You must be signed in to change notification settings - Fork 4.5k
(core): exportValue doesn't respect overridelogicalId #14335
Description
If we create a stack like:
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as iam from '@aws-cdk/aws-iam';
/**
* Stack that defines the bucket
*/
class Producer extends cdk.Stack {
public readonly myBucket: s3.Bucket;
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'MyBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
this.myBucket = bucket;
this.exportValue(bucket.bucketArn);
const cfnResource = bucket.node.defaultChild as s3.CfnBucket;
cfnResource.overrideLogicalId('OVERRIDE_LOGICAL_ID');
}
}
interface ConsumerProps extends cdk.StackProps {
userBucket: s3.IBucket;
}
/**
* Stack that consumes the bucket
*/
class Consumer extends cdk.Stack {
constructor(scope: cdk.App, id: string, props: ConsumerProps) {
super(scope, id, props);
const user = new iam.User(this, 'MyUser');
props.userBucket.grantReadWrite(user);
}
}
const app = new cdk.App();
const producer = new Producer(app, 'ProducerStack');
new Consumer(app, 'ConsumerStack', { userBucket: producer.myBucket });If we synth that, we get this in Producer:
"ExportsOutputFnGetAttMyBucketF68F3FF0Arn0F7E8E58": {
"Value": {
"Fn::GetAtt": [
"OVERRIDE_LOGICAL_ID",
"Arn"
]
},
"Export": {
"Name": "ProducerStack:ExportsOutputFnGetAttMyBucketF68F3FF0Arn0F7E8E58"
}
},
"ExportsOutputFnGetAttOVERRIDELOGICALIDArn49941B8D": {
"Value": {
"Fn::GetAtt": [
"OVERRIDE_LOGICAL_ID",
"Arn"
]
},
"Export": {
"Name": "ProducerStack:ExportsOutputFnGetAttOVERRIDELOGICALIDArn49941B8D"
}
}As you can see, both of these have the same value, but different names. Consumer uses the output with the overridden ID:
{
"Fn::ImportValue": "ProducerStack:ExportsOutputFnGetAttOVERRIDELOGICALIDArn49941B8D"
},Some other cases:
- If we comment out
overrideLogicalIdwe get onlyExportsOutputFnGetAttMyBucketF68F3FF0Arn0F7E8E58in both stacks - If we keep the override but remove the reference in
Consumerwe get only theExportsOutputFnGetAttMyBucketF68F3FF0Arn0F7E8E58Output inProducer - If we move the
exportValueafter theoverrideLogicalIdwe get onlyExportsOutputFnGetAttOVERRIDELOGICALIDArn49941B8Din both stacks
So, basically, it seems like exportValue creates the name for the initial logicalId and that doesn't change when it gets overridden. References in other stacks will create Outputs based on the new logicalId, ignoring the ones created by exportValue.
I believe this makes it a bit harder to use exportValue to avoid the deadly embrace, because the Outputs it generates in this case aren't the ones imported in a dependent's stack.
Reproduction Steps
I just created a file with the above and passed it to a cdk synth --app 'yarn babel-node my-file.ts'.
What did you expect to happen?
I'd expect just a single Output.
What actually happened?
Two Outputs get created, Consumer does not reference the Output created with createExports, it references a lazily created Output that includes the overridden logicalId in its name.
Environment
- CDK CLI Version : 1.91.0 and 1.100.0
- Framework Version: 1.91.0 and 1.100.0
- Node.js Version: v10.19.0
- OS : MacOS 10.15.7
- Language (Version): TypeScript (4.0.2)
Other
It's worth noting that this is pretty easy to work around - you just have to call exportValue after overrideLogicalId.
This is 🐛 Bug Report