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

[redshift] Cyclic dependency between redshift and lambda in different stacks #10547

Closed
alex9311 opened this issue Sep 25, 2020 · 5 comments
Closed
Assignees
Labels
@aws-cdk/aws-redshift Related to Amazon Redshift bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@alex9311
Copy link
Contributor

alex9311 commented Sep 25, 2020

using allow_default_port_from on a redshift cluster in in the other stack creates a cyclic reference

Reproduction Steps

from aws_cdk import core
from aws_cdk import aws_redshift
from aws_cdk import aws_lambda
from aws_cdk import aws_ec2


app = core.App()

cluster_stack = core.Stack(app, "stack1")
lambda_stack = core.Stack(app, "stack2")

vpc = aws_ec2.Vpc(cluster_stack, "vpc")
cluster = aws_redshift.Cluster(
        cluster_stack,
        "redshift-cluster",
        master_user=(aws_redshift.Login(master_username='master_username')),
        vpc=vpc)

lambda_function = aws_lambda.Function(lambda_stack, "lambdaFunction",
  code= aws_lambda.Code.from_inline("whatever"),
  handler="index.handler",
  runtime=aws_lambda.Runtime.NODEJS_10_X,
  vpc=vpc
)

cluster.connections.allow_default_port_from(lambda_function)

app.synth()

What did you expect to happen?

I want to define my cluster in one stack and my lambda functions that access it in another

What actually happened?

jsii.errors.JSIIError: 'stack1' depends on 'stack2' (stack1 -> stack2/lambdaFunction/SecurityGroup/Resource.GroupId). Adding this dependency (stack2 -> stack1/vpc/Resource.Ref) would create a cyclic reference.
Subprocess exited with error 1

Environment

  • CLI Version : 1.47.1
  • Framework Version: 1.64.1
  • Node.js Version: v10.15.3
  • OS : ubuntu 18.04
  • Language (Version): python3.8

Other


This is 🐛 Bug Report

@alex9311 alex9311 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Sep 25, 2020
@SomayaB SomayaB changed the title Cyclic dependency between redshift and lambda in different stacks [redshift] Cyclic dependency between redshift and lambda in different stacks Sep 29, 2020
@github-actions github-actions bot added the @aws-cdk/aws-redshift Related to Amazon Redshift label Sep 29, 2020
@njlynch
Copy link
Contributor

njlynch commented Sep 30, 2020

Thanks for the report and repro steps.

It looks like the cluster stack is (rightly) taking a dependency on the Lambda's security groups, and the Lambda stack has a dependency on the VPC.

Do you have some flexibility in how you set up your infrastructure? My first recommendation would actually be to create the VPC in its own stack. Often, VPCs have different lifecycles than the other components of an app anyway -- very long-lived and slow-moving vs the faster development of the components. One approach that works here would be to do this:

vpc_stack = core.Stack(app, "vpc_stack")
vpc = aws_ec2.Vpc(vpc_stack, "vpc")

Then use the VPC as you are currently doing in both the other stacks. This would fix the cyclic dependency.

The other option would be to define the VPC in your Lambda stack, if that makes sense for your architecture.

Do either of those work for you?

@njlynch njlynch added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Sep 30, 2020
@alex9311
Copy link
Contributor Author

Hi @njlynch, thanks for the detailed response! Adding a third stack with just the VPC seems like a great solution -- I'll try that.

Thanks!

@alex9311
Copy link
Contributor Author

alex9311 commented Sep 30, 2020

Sorry to re-open, the third stack for the VPC solved one of my issues but I quickly ran into another cyclic dependency issue

I'm trying to pass the cluster hostname to my lambda function as an environment variable. If both the cluster.connections.allow_default_port_from(lambda_function) and the cluster.cluster_endpoint.hostname in stack1's lambda are used, a cyclic error is returned when I synth

jsii.errors.JSIIError: 'stack1' depends on 'stack2' (stack1 -> stack2/lambdaFunction/SecurityGroup/Resource.GroupId). Adding this dependency (stack2 -> stack1/redshift-cluster/Resource.Endpoint.Address) would create a cyclic reference.

I suppose this makes sense but it seems like a common enough use-case, no? It doesn't look like the cluster hostname is something I can hard-code in my cdk.json and pass to both stacks. Any suggestions on how to architect this sort of thing?

from aws_cdk import core
from aws_cdk import aws_redshift
from aws_cdk import aws_lambda
from aws_cdk import aws_ec2


app = core.App()

vpc_stack = core.Stack(app, "stack0")
vpc = aws_ec2.Vpc(vpc_stack, "vpc")

cluster_stack = core.Stack(app, "stack1")
cluster = aws_redshift.Cluster(
    cluster_stack,
    "redshift-cluster",
    master_user=(aws_redshift.Login(master_username='master_username')),
    vpc=vpc)

lambda_stack = core.Stack(app, "stack2")
lambda_function = aws_lambda.Function(
    lambda_stack,
    "lambdaFunction",
    code= aws_lambda.Code.from_inline("whatever"),
    handler="index.handler",
    runtime=aws_lambda.Runtime.NODEJS_10_X,
    vpc=vpc,
    environment= {
        "REDSHIFT_CLUSTER_HOST": cluster.cluster_endpoint.hostname
    }
)

cluster.connections.allow_default_port_from(lambda_function)

app.synth()

@alex9311 alex9311 reopened this Sep 30, 2020
@njlynch
Copy link
Contributor

njlynch commented Sep 30, 2020

Hey @alex9311 , can you give this a shot?

from aws_cdk import core
from aws_cdk import aws_redshift
from aws_cdk import aws_lambda
from aws_cdk import aws_ec2

app = core.App()

vpc_stack = core.Stack(app, "stack0")
vpc = aws_ec2.Vpc(vpc_stack, "vpc")

cluster_stack = core.Stack(app, "stack1")
cluster = aws_redshift.Cluster(
    cluster_stack,
    "redshift-cluster",
    master_user=(aws_redshift.Login(master_username='master_username')),
    vpc=vpc)

lambda_stack = core.Stack(app, "stack2")
lambda_function = aws_lambda.Function(
    lambda_stack,
    "lambdaFunction",
    code= aws_lambda.Code.from_inline("whatever"),
    handler="index.handler",
    runtime=aws_lambda.Runtime.NODEJS_10_X,
    vpc=vpc,
    environment= {
        "REDSHIFT_CLUSTER_HOST": cluster.cluster_endpoint.hostname
    }
)

# Flip the order of the connection to change which stack owns the resource
# cluster.connections.allow_default_port_from(lambda_function) 
lambda_function.connections.allow_to(cluster, aws_ec2.Port.tcp(cluster.cluster_endpoint.port))

app.synth()

See #1654 (comment) for some background on this decision.

@alex9311
Copy link
Contributor Author

@njlynch that works great! Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-redshift Related to Amazon Redshift bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
Development

No branches or pull requests

2 participants