(opensearch): Trying to define an Opensearch domain in one stack and reference it in another causes cyclic reference errors
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 71
Description
### Describe the bug
I want to use the classic pattern where you have an infrastructure stack and a code stack.
I define an Opensearch domain in my infrastructure stack in a VPC. I then define a code stack, and attempt to wire up a Lambda that uses that domain.
This works when all the resources are in one stack; or if the code stack is nested in the infrastructure stack. But if they're peer stacks I get a cyclic reference stack.
For the reproduction provided below, the error is:
```
'InfrastructureStack' depends on 'CodeStack' (InfrastructureStack -> CodeStack/LambdaFunction/SecurityGroup/Resource.GroupId). Adding this dependency (CodeStack -> InfrastructureStack/OpensearchDomain/Resource.Arn) would create a cyclic reference.
```
### Expected Behavior
For all the resources related to my Lambda to be defined in the Code stack, so there's no cyclic references. That's what I'd do if I was writing the Cloudformation directly.
### Current Behavior
The lambda function itself is defined in the code stack Cloudformation. However, the AWS::EC2::SecurityGroupIngress allowing the lambda function ingress to the Opensearch domain is defined in the infrastructure stack Cloudformation.
### Reproduction Steps
The simplest reproduction I could come up with is to generate a new python application using `cdk init app --language python`, and then update app.py to be:
```
#!/usr/bin/env python3
import aws_cdk as cdk
from aws_cdk import aws_opensearchservice, aws_lambda, aws_ec2
from constructs import Construct
class InfrastructureStack(cdk.Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
self._vpc = aws_ec2.Vpc(
scope=self,
id="Vpc",
cidr="10.64.0.0/16",
)
self._domain = aws_opensearchservice.Domain(
scope=self,
id="OpensearchDomain",
version=aws_opensearchservice.EngineVersion.OPENSEARCH_1_2,
vpc=self._vpc,
)
@property
def domain(self) -> aws_opensearchservice.Domain:
return self._domain
@property
def vpc(self) -> aws_ec2.IVpc:
return self._vpc
class CodeStack(cdk.Stack):
def __init__(self,
scope: Construct,
construct_id: str,
domain: aws_opensearchservice.Domain,
vpc: aws_ec2.IVpc,
**kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
self._lambda_function = aws_lambda.Function(
scope=self,
id="LambdaFunction",
handler="index.handler",
runtime=aws_lambda.Runtime.PYTHON_3_9,
code=aws_lambda.Code.from_inline("handler code goes here"),
environment={
"OPENSEARCH_ENDPOINT": domain.domain_endpoint,
},
vpc=vpc,
)
domain.connections.allow_from(self._lambda_function, aws_ec2.Port.tcp(443))
domain.grant_read_write(self._lambda_function)
app = cdk.App()
infrastructure_stack = InfrastructureStack(app, "InfrastructureStack")
CodeStack(app, "CodeStack", infrastructure_stack.domain, infrastructure_stack.vpc)
app.synth()
```
### Possible Solution
For all the resources related to my Lambda to be defined in the Code stack, so there's no cyclic references. That's what I'd do if I was writing the Cloudformation directly.
### Additional Information/Context
_No response_
### CDK CLI Version
2.23.0 (build 50444aa)
### Framework Version
2.24.0
### Node.js Version
14.17.0
### OS
Ubuntu (Windows Subsystem for Linux)
### Language
Python
### Language Version
3.9.7
### Other information
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.