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

fix(core): cross-stack references to NestedStack list values produces invalid outputs #32575

Merged
merged 5 commits into from
Feb 25, 2025

Conversation

brandondahler
Copy link
Contributor

Issue

Closes #27233.

Reason for this change

Referencing a list attribute of a resource defined within a NestedStack synthesizes successfully but the nested stack will fail deployment with the error:

Template format error: Every Value member must be a string.

This prevents deploying resources into a NestedStack instance if a reference to one of that resource's list attribute exists within a cross-stack context. For example, deploying a InterfaceVpcEndpoint instance in a nested stack and attempting to reference its vpcEndpointDnsEntries property within a different stack will cause this error.

See new integration test at packages/@aws-cdk-testing/framework-integ/test/core/test/integ.nested-stack-references.ts for minimal reproduction.

Description of changes

A similar strategy to exportStringListValue is used to serialized the reference's values into a string and expose that value as the output from the nested stack. The reference to the serialized value is then made exportable as normally needed to hoist it to the top-level parent stack. The final reference that imports the value is then re-written to also deserialize the imported string back to the original list.

The return types of some internal methods were modified to handle the fact that core/lib/private/refs.ts's getExportable no longer necessarily returns a Reference. This was needed because an exportable may now be a value derived from a reference instead of only a direct reference.

Describe any new or updated permissions being added

N/A

Description of how you validated changes

  • Added unit test to verify low-level operation
  • Added integration test to verify high-level behavior and deploy-ability
    • Executed integration test within a personal account to verify success

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@brandondahler brandondahler requested a review from a team as a code owner December 18, 2024 15:18
@github-actions github-actions bot added bug This issue is a bug. p2 beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK labels Dec 18, 2024
@aws-cdk-automation aws-cdk-automation requested a review from a team December 18, 2024 15:18
@brandondahler brandondahler changed the title fix(core): cross-stack references to NestedStack list values produces invalid outputs (#27233) fix(core): cross-stack references to NestedStack list values produces invalid outputs Dec 18, 2024
@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Dec 18, 2024
Copy link
Contributor

@nmussy nmussy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nits about coverage, LGTM overall though 👍

… invalid outputs

Referencing a list attribute of a resource defined within a NestedStack synthesizes successfully but the nested stack will fail deployment with the error:

```
Template format error: Every Value member must be a string.
```

This prevents deploying resources such into NestedStack instances if a reference to that resource's list attribute needs to be referenced in a cross-stack context.  For example, deploying a `InterfaceVpcEndpoint` instance in a nested stack and attempting to reference its `vpcEndpointDnsEntries` property within a different stack will cause this error.

To fix this issue, a similar strategy to `exportStringListValue` is used to join the reference's values into a string and expose that value as the output from the nested stack.  The reference to the serialized value is then re-exported as normally needed to hoist it to the top-level parent stack.  The final reference that imports the value is then re-written to also deserialize the imported string back to the original list.

fixes aws#27233

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@brandondahler brandondahler force-pushed the features/NestedStackListReference branch from 8219bff to 28721e3 Compare December 20, 2024 00:51
@aws-cdk-automation aws-cdk-automation removed the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Dec 20, 2024
Copy link
Contributor

@nmussy nmussy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the changes

@aws-cdk-automation aws-cdk-automation added the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Feb 17, 2025
Copy link
Contributor

@kaizencc kaizencc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for the super late review @brandondahler. my main concern is the change between Reference and Intrinsic. Let's figure that out, and then I'm happy to send this one into main!

@@ -321,17 +334,23 @@ function createNestedStackOutput(producer: Stack, reference: Reference): CfnRefe
*
* Will create Outputs along the chain of Nested Stacks, and return the final `{ Fn::GetAtt }`.
*/
export function referenceNestedStackValueInParent(reference: Reference, targetStack: Stack) {
export function referenceNestedStackValueInParent(reference: Reference, targetStack: Stack): Intrinsic {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we returning an Intrinsic here? it should be a Reference right.

Copy link
Contributor Author

@brandondahler brandondahler Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to use Intrinsic here because we're reversing the tokenized list via Fn.split (line 354). We're having to use Fn.split because we're having to do a join when creating the output within the nested stack since the output cannot be a list.

Prior to this update, the values returned from here were only able to reference strings and therefore were just outer stack Reference's to the nested stack's resource attribute. After this update, the values returned from here may either reference a string or a list. In the list case, it is an implementation detail of this method that we're having to re-split the Reference on the nested stack's resource out to its list representation again (and therefore are returning an Intrinsic instead).

Ultimately the choice from a type perspective was either returning an Intrinsic or an IResolvable, either would be correct per the type hierarchies involved.

@@ -260,7 +269,7 @@ function generateExportName(importStack: Stack, reference: Reference, id: string
return prefix + localPart.slice(Math.max(0, localPart.length - maxLength + prefix.length));
}

export function getExportable(stack: Stack, reference: Reference): Reference {
export function getExportable(stack: Stack, reference: Reference): Intrinsic {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i understand that this is a private function but I am concerned about the downgrade from returning a Reference to an Intrinsic. i want to learn more about why thats something you've deemed necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ultimately changed because referenceNestedStackValueInParent changed, see that comment for more details. TL;DR Fn.split returns an Intrinsic (not a Reference) when untokenized.

@samson-keung samson-keung added the skip-abstractions-board signal to automated workflow to skip adding to project board label Feb 19, 2025
Copy link
Contributor

@kaizencc kaizencc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @brandondahler!

Copy link
Contributor

mergify bot commented Feb 24, 2025

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

Copy link
Contributor

mergify bot commented Feb 24, 2025

This pull request has been removed from the queue for the following reason: pull request branch update failed.

The pull request can't be updated

You should look at the reason for the failure and decide if the pull request needs to be fixed or if you want to requeue it.

If you want to requeue this pull request, you need to post a comment with the text: @mergifyio requeue

@aws-cdk-automation aws-cdk-automation removed the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Feb 24, 2025
Copy link
Contributor

mergify bot commented Feb 24, 2025

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@brandondahler
Copy link
Contributor Author

@Mergifyio requeue

Copy link
Contributor

mergify bot commented Feb 24, 2025

requeue

❌ Command disallowed due to command restrictions in the Mergify configuration.

  • sender-permission >= write

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: 8968e4a
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

mergify bot commented Feb 25, 2025

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit f9252ab into aws:main Feb 25, 2025
10 checks passed
Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 25, 2025
@brandondahler brandondahler deleted the features/NestedStackListReference branch February 25, 2025 17:15
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK bug This issue is a bug. p2 skip-abstractions-board signal to automated workflow to skip adding to project board
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(cloudformation-include): Cannot use computed outputs from nested stack
5 participants