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

cyclic reference when API and Lambda are in different stacks (Python code) #3000

Closed
1 of 5 tasks
bgdnlp opened this issue Jun 21, 2019 · 6 comments
Closed
1 of 5 tasks
Assignees
Labels
@aws-cdk/aws-apigateway Related to Amazon API Gateway bug This issue is a bug. p1

Comments

@bgdnlp
Copy link

bgdnlp commented Jun 21, 2019

  • I'm submitting a ...

    • πŸͺ² bug report
    • πŸš€ feature request
    • πŸ“š construct library gap
    • ☎️ security issue or vulnerability => Please see policy
    • ❓ support request => Please see note at the top of this template.
  • What is the current behavior?
    Python code to reproduce:

#!/usr/bin/env python3
from aws_cdk import cdk
from aws_cdk import aws_lambda
from aws_cdk import aws_iam
from aws_cdk import aws_apigateway


class LambdaStack(cdk.Stack):
    def __init__(self, app, id, **kwargs):
        super().__init__(app, id, **kwargs)

        self.lambda_func = aws_lambda.Function(
            self,
            id="LambdaFunc",
            code=aws_lambda.AssetCode('lambda'),
            handler='placeholder.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON37,
            role=aws_iam.Role.from_role_arn(
                self,
                'nonexistent',
                'arn:aws:iam::617845755280:role/dummy'),
            function_name='lambda-func')


class APIStack(cdk.Stack):
    def __init__(self, app, id, **kwargs):
        super().__init__(app, id, **kwargs)
        self.apigw_handler = None

    def run_after_function_is_set(self):
        self.apigw = aws_apigateway.LambdaRestApi(
                self,
                'APIGw',
                handler=self.apigw_handler)


app = cdk.App()
LambdaStk = LambdaStack(app, "LambdaStack")
APIStk = APIStack(app, "APIStack")
APIStk.apigw_handler = LambdaStk.lambda_func
APIStk.run_after_function_is_set()

app.synth()

Results in:

jsii.errors.JavaScriptError:
Error: 'APIStack' depends on 'LambdaStack' (APIStack/APIGw/Default/{proxy+}/ANY/Resource
-> LambdaStack/LambdaFunc/Resource.Arn). Adding this dependency
(LambdaStack/LambdaFunc/ApiPermission.ANY.. -> APIStack/APIGw/Resource.Ref)
would create a cyclic reference.
  • What is the expected behavior (or behavior of feature suggested)?
    Maybe I'm doing something wrong? I would expect that code to work.

  • What is the motivation / use case for changing the behavior or adding this feature?
    Once the APIs are stable the code changes much more often, so it would make sense to separate them in different stacks.

  • Please tell us about your environment:

    • CDK CLI Version: 0.35.0 (build c5e43e2)
    • Module Version: 0.35.0
    • OS: all
    • Language: Python, though the error comes from the underlying TypeScript
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, gitter, etc)

I'm creating the actual API outside of the stack's __init__ method in order to be able to set the LambdaRestApi handler first. I was a bit surprised that it seemed to work and I'm not sure it's the right approach, but I don't think that's what's causing the bug.

@NGL321 NGL321 added needs-triage This issue or PR still needs to be triaged. bug This issue is a bug. @aws-cdk/core Related to core CDK functionality language/python Related to Python bindings needs-reproduction This issue needs reproduction. and removed needs-triage This issue or PR still needs to be triaged. labels Jun 21, 2019
@fulghum fulghum added the p1 label Jun 26, 2019
@fulghum
Copy link
Contributor

fulghum commented Jun 26, 2019

Need to check for this condition and give a helpful error message

@nija-at
Copy link
Contributor

nija-at commented Sep 4, 2019

This issue isn't isolated to Python - it occurs even in a Typescript CDK app. This has to do with the way the API Gateway and Lambda constructs interplay.

When a Lambda function from one stack is referenced into an API Gateway integration on another stack, the latter stack takes a dependency on the former stack (as expected) by referencing the function handler's ARN or its ARN is referenced.

At the same time, the function handler construct is now updated with permissions to allow the API Gateway method to invoke the function, which depends on knowing the 'execute-api' ARN of the API Gateway 'Method'. In effect, the former stack now depends on the ARN generated by the latter stack.

This causes the cyclic dependency.

@nija-at nija-at added @aws-cdk/aws-apigateway Related to Amazon API Gateway and removed @aws-cdk/core Related to core CDK functionality language/python Related to Python bindings needs-reproduction This issue needs reproduction. labels Sep 4, 2019
@nija-at nija-at assigned nija-at and unassigned eladb Sep 4, 2019
nija-at pushed a commit that referenced this issue Sep 10, 2019
1. Token resolution of Deployment construct must not resolve the entire
   stack, specifically during the prepare phase.

   stack.resolve() works only after the CDK app has been fully prepared.
   During the 'prepare' phase, token resolution should instead resolve
   the token partially and within the local context.

2. Scope the lambda.CfnPermission construct closer to the consumer of
   the permission rather than being closer to the lambda function.

   For instance, when a lambda function is being consumed by an
   APIGateway RestApi Method as a cross-stack reference, placing the
   lambda.CfnPermission construct closer to the RestApi Method reduces
   the possibility of cyclic dependencies.

fixes #3705, #3000
nija-at pushed a commit that referenced this issue Sep 12, 2019
…n and/or creates cyclic references

1. Token resolution of Deployment construct must not resolve the entire
   stack, specifically during the prepare phase.

   stack.resolve() works only after the CDK app has been fully prepared.
   During the 'prepare' phase, token resolution should instead resolve
   the token partially and within the local context.

2. Scope the lambda.CfnPermission construct closer to the consumer of
   the permission rather than being closer to the lambda function.

   For instance, when a lambda function is being consumed by an
   APIGateway RestApi Method as a cross-stack reference, placing the
   lambda.CfnPermission construct closer to the RestApi Method reduces
   the possibility of cyclic dependencies.

fixes #3705, #3000
nija-at pushed a commit that referenced this issue Sep 12, 2019
…n and/or creates cyclic references

1. Token resolution of Deployment construct must not resolve the entire
   stack, specifically during the prepare phase.

   stack.resolve() works only after the CDK app has been fully prepared.
   During the 'prepare' phase, token resolution should instead resolve
   the token partially and within the local context.

2. Scope the lambda.CfnPermission construct closer to the consumer of
   the permission rather than being closer to the lambda function.

   For instance, when a lambda function is being consumed by an
   APIGateway RestApi Method as a cross-stack reference, placing the
   lambda.CfnPermission construct closer to the RestApi Method reduces
   the possibility of cyclic dependencies.

fixes #3705, #3000
nija-at added a commit that referenced this issue Sep 12, 2019
…ence (#4010)

1. Token resolution of Deployment construct must not resolve the entire
   stack, specifically during the prepare phase.

   stack.resolve() works only after the CDK app has been fully prepared.
   During the 'prepare' phase, token resolution should instead resolve
   the token partially and within the local context.

2. Scope the lambda.CfnPermission construct closer to the consumer of
   the permission rather than being closer to the lambda function.

   For instance, when a lambda function is being consumed by an
   APIGateway RestApi Method as a cross-stack reference, placing the
   lambda.CfnPermission construct closer to the RestApi Method reduces
   the possibility of cyclic dependencies.

fixes #3705, #3000
@nija-at
Copy link
Contributor

nija-at commented Sep 12, 2019

#4010

@nija-at nija-at closed this as completed Sep 12, 2019
@advaj
Copy link

advaj commented Nov 22, 2019

This error seems to be occurring between Lambda and Cloudwatch Event rules as well. We have a main stack in which we have two child stacks. One of which is used to create Lambda Functions. In another stack, we create Cloudwatch event rules with the Lambda functions as Targets. And we see the same error. Can someone explain whether the fix above is only between API GW, Lambda?

@nija-at
Copy link
Contributor

nija-at commented Nov 22, 2019

@advaj - Yes, the above fix is only between APIGateway and Lambda. Please report this a separate issue with enough code to reproduce this. Thanks.

@charliebsimms
Copy link

I am importing aws_apigateway to use SpecRestApi and I am getting the cyclic reference error. aws_apigatewayv2 does not reference SpecRestApi. How do I resolve the issue issue when trying to add_permission to the lambda? I am using the latest aws-cdk-lib==2.88.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-apigateway Related to Amazon API Gateway bug This issue is a bug. p1
Projects
None yet
Development

No branches or pull requests

8 participants