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

(Core): unexpected logical id change for CdkJsonStringify when order of stack changed #31345

Closed
1 task
Wurstnase opened this issue Sep 6, 2024 · 3 comments · Fixed by #31470 or softwaremill/tapir#4137 · May be fixed by NOUIY/aws-solutions-constructs#135 or NOUIY/aws-solutions-constructs#136
Assignees
Labels
@aws-cdk/core Related to core CDK functionality bug This issue is a bug. effort/medium Medium work item – several days of effort p1

Comments

@Wurstnase
Copy link
Contributor

Describe the bug

The logical id of a CdkJsonStringify will change for different stacks, when the order of stacks will change.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

Order of stack shouldn't change the logical id.

Current Behavior

The logical id in CdkJsonStringify<id> is stack order dependend.

Reproduction Steps

Synth the following app twice:

Python app
#!/usr/bin/env python3

import os
import aws_cdk as cdk

from aws_cdk import (
    CfnOutput,
    Fn,
    Stack,
    custom_resources as cr,
    aws_ec2 as ec2,
)
from constructs import Construct


class CdkMinimalStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        vpc = ec2.Vpc.from_lookup(self, "Vpc", vpc_name="VPC1-VPC")

        vpc_endpoint = ec2.InterfaceVpcEndpoint(
            self,
            "VpcEndpoint",
            vpc=vpc,
            service=ec2.InterfaceVpcEndpointAwsService.APIGATEWAY,
        )

        eni_ids = vpc_endpoint.vpc_endpoint_network_interface_ids
        output_paths = [f"NetworkInterfaces.{id}.PrivateIpAddress" for id in range(3)]

        describe_network_interfaces_response = cr.AwsCustomResource(
            self,
            "DescribeEnis",
            on_update=cr.AwsSdkCall(
                api_version="v3",
                service="ec2",
                action="describeNetworkInterfaces",
                output_paths=output_paths,
                parameters={"NetworkInterfaceIds": eni_ids},
                physical_resource_id=cr.PhysicalResourceId.of(Fn.join("-", eni_ids)),
            ),
            policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
                resources=cr.AwsCustomResourcePolicy.ANY_RESOURCE
            ),
        )
        ips = [
            describe_network_interfaces_response.get_response_field(op)
            for op in output_paths
        ]

        CfnOutput(
            self,
            "Ips",
            value=Fn.join(
                ",",
                ips,
            ),
        )


app = cdk.App()

if os.getenv("DEFAULT", "true") == "true":
    CdkMinimalStack(
        app,
        "Stack1",
        env=cdk.Environment(account="111122223333", region="eu-central-1"),
    )
CdkMinimalStack(
    app,
    "Stack2",
    env=cdk.Environment(account="222233334444", region="eu-central-1"),
)
if os.getenv("DEFAULT", "false") != "true":
        CdkMinimalStack(
        app,
        "Stack1",
        env=cdk.Environment(account="111122223333", region="eu-central-1"),
    )
app.synth()
DEFAULT=true cdk synth
grep CdkJsonStringify -r cdk.out
DEFAULT=true
cdk.out/Stack2.template.json:         "CdkJsonStringify2",
cdk.out/Stack2.template.json:         "CdkJsonStringify2",
cdk.out/Stack2.template.json:  "CdkJsonStringify2": {
cdk.out/Stack2.template.json:    "aws:cdk:path": "Stack2/CdkJsonStringify2/Default"
cdk.out/Stack1.template.json:         "CdkJsonStringify1",
cdk.out/Stack1.template.json:         "CdkJsonStringify1",
cdk.out/Stack1.template.json:  "CdkJsonStringify1": {
cdk.out/Stack1.template.json:    "aws:cdk:path": "Stack1/CdkJsonStringify1/Default"
cdk.out/manifest.json:        "/Stack1/CdkJsonStringify1/Default": [
cdk.out/manifest.json:            "data": "CdkJsonStringify1"
cdk.out/manifest.json:        "/Stack2/CdkJsonStringify2/Default": [
cdk.out/manifest.json:            "data": "CdkJsonStringify2"
cdk.out/tree.json:          "CdkJsonStringify1": {
cdk.out/tree.json:            "id": "CdkJsonStringify1",
cdk.out/tree.json:            "path": "Stack1/CdkJsonStringify1",
cdk.out/tree.json:                "path": "Stack1/CdkJsonStringify1/Default",
cdk.out/tree.json:          "CdkJsonStringify2": {
cdk.out/tree.json:            "id": "CdkJsonStringify2",
cdk.out/tree.json:            "path": "Stack2/CdkJsonStringify2",
cdk.out/tree.json:                "path": "Stack2/CdkJsonStringify2/Default",
DEFAULT=false cdk synth
grep CdkJsonStringify -r cdk.out
DEFAULT=false
cdk.out/Stack2.template.json:         "CdkJsonStringify1",
cdk.out/Stack2.template.json:         "CdkJsonStringify1",
cdk.out/Stack2.template.json:  "CdkJsonStringify1": {
cdk.out/Stack2.template.json:    "aws:cdk:path": "Stack2/CdkJsonStringify1/Default"
cdk.out/Stack1.template.json:         "CdkJsonStringify2",
cdk.out/Stack1.template.json:         "CdkJsonStringify2",
cdk.out/Stack1.template.json:  "CdkJsonStringify2": {
cdk.out/Stack1.template.json:    "aws:cdk:path": "Stack1/CdkJsonStringify2/Default"
cdk.out/manifest.json:        "/Stack2/CdkJsonStringify1/Default": [
cdk.out/manifest.json:            "data": "CdkJsonStringify1"
cdk.out/manifest.json:        "/Stack1/CdkJsonStringify2/Default": [
cdk.out/manifest.json:            "data": "CdkJsonStringify2"
cdk.out/tree.json:          "CdkJsonStringify1": {
cdk.out/tree.json:            "id": "CdkJsonStringify1",
cdk.out/tree.json:            "path": "Stack2/CdkJsonStringify1",
cdk.out/tree.json:                "path": "Stack2/CdkJsonStringify1/Default",
cdk.out/tree.json:          "CdkJsonStringify2": {
cdk.out/tree.json:            "id": "CdkJsonStringify2",
cdk.out/tree.json:            "path": "Stack1/CdkJsonStringify2",
cdk.out/tree.json:                "path": "Stack1/CdkJsonStringify2/Default",

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.156.0 (build 2966832)

Framework Version

No response

Node.js Version

v20.17.0

OS

macOS 14.6.1

Language

Python

Language Version

3.12.5

Other information

No response

@Wurstnase Wurstnase added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Sep 6, 2024
@github-actions github-actions bot added the @aws-cdk/core Related to core CDK functionality label Sep 6, 2024
@pahud pahud self-assigned this Sep 9, 2024
@pahud
Copy link
Contributor

pahud commented Sep 10, 2024

Yes I can reproduce this.

Looks like when you deploy 2 stacks, the stack order ID would be appended to the logicalId of Custom::AWSCDKCfnJsonStringify and you get CdkJsonStringify1 and CdkJsonStringify2.

Now if you re-deploy the 2nd stack only the logicalId would change, causing unnecessary custom resource update which could have been avoided.

image image

I believe the root cause is around here:

CfnUtils.stringify(stack, `CdkJsonStringify${stringifyCounter++}`, intrinsic),

@pahud pahud added p1 effort/medium Medium work item – several days of effort and removed needs-triage This issue or PR still needs to be triaged. labels Sep 10, 2024
@pahud pahud removed their assignment Sep 10, 2024
@comcalvi comcalvi self-assigned this Sep 25, 2024
@mergify mergify bot closed this as completed in #31470 Oct 1, 2024
@mergify mergify bot closed this as completed in 4128bf1 Oct 1, 2024
Copy link

github-actions bot commented Oct 1, 2024

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.

1 similar comment
Copy link

github-actions bot commented Oct 1, 2024

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 Oct 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.