aws-s3-assets : Upgrading from LegacyStackSynthesizer to DefaultStackSynthesizer with cross-stack reference causes UpdateFailed
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 74
Description
### Describe the bug
When upgrading from the `LegacyStackSynthesizer` to the `DefaultStackSynthesizer`, cross-stack asset dependencies cause deployment to fail with the following exception:
`Export ProducingStack:ExportsOutputRefAssetParameters6547f4c9757e3c9a9d37d7a5d75004ce634cb9b01af7a7606412c36b947f248fS3BucketA01FB337B366B8FA cannot be deleted as it is in use by ConsumingStack
`
The issue of redeployment failing after removing generic cross-stack dependencies is described in #3414. In this specific case, CDK's legacy synthesizer creates an `AssetParameters` export in the producing stack so that it can be used in the consuming stack. However, the `DefaultStackSynthesizer` does not create this export. The result is that when upgrading from the `DefaultStackSynthesizer` to the `LegacyStackSynthesizer`, the deployment fails because the producing stack's export cannot be deleted while referenced by the consuming stack.
### Expected Behavior
Deployment succeeds when updating an app with cross-stack asset dependencies from the `LegacyStackSynthesizer` to the `DefaultStackSynthesizer`.
### Current Behavior
Deployment fails to update the producing stack
### Reproduction Steps
Define stack classes as follows:
```
import os
from constructs import Construct
from aws_cdk import (
App,
Stack,
CfnOutput,
Fn,
LegacyStackSynthesizer,
StackProps
)
from aws_cdk.aws_s3 import (
Bucket,
)
from aws_cdk.aws_s3_assets import (
Asset,
)
from aws_cdk.aws_lambda import (
Function,
Code,
Runtime
)
class ProducingStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
bucket = Bucket(self, "My Bucket")
self.bucket = bucket
dirname = os.path.dirname(__file__)
asset = Asset(self, "MyImageAsset", path=os.path.join(dirname, "asset.png"))
self.asset=asset
class ConsumingStack(Stack):
def __init__(self, scope: Construct, construct_id: str, bucket, asset, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
lambda_func = Function( self, "My Function", code=Code.from_inline("handler = lambda event, context : {}"), handler="index.handler", runtime=Runtime.PYTHON_3_7)
bucket.grant_read_write(lambda_func)
asset.grant_read(lambda_func)
app = App()
```
Deploy with stacks defined using `LegacyStackSynthesizer`:
```
producing_stack = ProducingStack(app, "ProducingStack", synthesizer=LegacyStackSynthesizer())
ConsumingStack(app, "ConsumingStack", producing_stack.bucket, producing_stack.asset, synthesizer=LegacyStackSynthesizer())
app.synth()
```
Deploy with stacks defined without synthesizer specified, defaulting to `DefaultStackSynthesizer`:
```
producing_stack = ProducingStack(app, "ProducingStack")
ConsumingStack(app, "ConsumingStack", producing_stack.bucket, producing_stack.asset)
app.synth()
```
### Possible Solution
_No response_
### Additional Information/Context
_No response_
### CDK CLI Version
2.61.0
### Framework Version
_No response_
### Node.js Version
v19.4.0
### OS
Same behavior on MacOS and AL2
### Language
Python
### Language Version
3.10.9
### Other information
_No response_
Contributor guide
Research direction
Start with the LegacyStackSynthesizer and DefaultStackSynthesizer entry points and the aws_s3_assets.Asset cross-stack dependency in the provided Python reproduction. Synthesize and deploy the ProducingStack and ConsumingStack with each synthesizer, then verify that upgrading to DefaultStackSynthesizer completes without UpdateFailed or an in-use export deletion error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python
- Domain
- cloud, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100