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

APIGateway and Lambdas in separate stacks fails #3705

Closed
vertti opened this issue Aug 19, 2019 · 8 comments · Fixed by #4010
Closed

APIGateway and Lambdas in separate stacks fails #3705

vertti opened this issue Aug 19, 2019 · 8 comments · Fixed by #4010
Assignees
Labels
@aws-cdk/aws-apigateway Related to Amazon API Gateway bug This issue is a bug.

Comments

@vertti
Copy link

vertti commented Aug 19, 2019

🐛 Bug Report

What is the problem?

I have what I would expect a very typical scenario: APIGateway that exposes several of my lambdas. I frequently have to delete the whole stack and would like to avoid destroying the APIGateway (so as not to change the URL and apikeys). So I wanted to split them to two stacks, one for the APIGateway and one for Lambdas. I first tried with CDK 1.1.0. This caused cyclic dependency errors (which I mentioned here. In hopes of it being fixed, I upgraded to 1.4.0. Now with the same setup I get:

cfn-reference.ts:108
      throw new Error(`Cross-stack reference (${context.scope.node.path} -> ${this.target.node.path}) has not been assigned a value--call prepare() first`);
            ^
Error: Resolution error: Resolution error: Resolution error: Cross-stack reference (ipk-PostiKioskiBackendStack-development -> ipk-PostiKioskiLambdaStack-development/ipk-ConfigLambda-development/Resource) has not been assigned a value--call prepare() first.
Object creation stack:
  at new Intrinsic (/Users/vertti/dev/posti/itsepalvelu-posti/posti-kioski-backend/node_modules/@aws-cdk/core/lib/private/intrinsic.ts:28:26)
  at new Reference (/Users/vertti/dev/posti/itsepalvelu-posti/posti-kioski-backend/node_modules/@aws-cdk/core/lib/reference.ts:21:5)

Reproduction Steps

Backend defined with:

const app = new core.App()
const stackLambda = new PostiKioskiLambdaStack(app, `ipk-PostiKioskiLambdaStack-${environment}`)
const stackBE = new PostiKioskiBackendStack(app, `ipk-PostiKioskiBackendStack-${environment}`, { configLambda: stackLambda.configLambda })

where PostiKioskiLambdaStack creates a lambda to a public configLambda property which is given in the props to stackBE.

The lambda in question is put inside a specific vpc:

    this.configLambda = new awsLambda.Function(this, `ipk-ConfigLambda-${environment}`, {
      role,
      vpc,

      code: awsLambda.Code.asset('resources'),
      handler: 'config_lambda.handler',
      runtime: awsLambda.Runtime.NODEJS_10_X,
    })

Verbose Log

https://gist.github.com/vertti/4883548b587774d1f1d2a75e78b640a1

Environment

  • CDK CLI Version: 1.4.0 (build 175471f)
  • OS: OSX Mojave
  • Language: TypeScript

Other information

There's been lots of fixes done for similar cases where Lambdas are in one stack and for example SNS is in another, all of those seemed to cause cyclic dependency errors.

@vertti vertti added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Aug 19, 2019
@whao
Copy link

whao commented Aug 20, 2019

I am having the exact same issue. I put all lambda functions into an object

export interface Function {
  [name: string]: lambda.Function;
}

and exposed it by

public readonly functions: Function = {};

and add function to it in constructor

this.functions.testNpmModulesLambda = testNpmModulesLambda;

@nodesmichael
Copy link

Same issue for me. I just refactored the RestApi creation into it's own stack, and all resource related stacks attempt to add resources and methods to it. But I get

'DevEnvironmentsRawDataStack' depends on 'DevEnvironmentsApiStack' (DevEnvironmentsRawDataStack/StoreRawData/ApiPermission.POST..raw-data -> DevEnvironmentsApiStack/Api/Resource.Ref). Adding this dependency (DevEnvironmentsApiStack/Api/Default/raw-data/get/Resource -> DevEnvironmentsRawDataStack/GetRawData/Resource.Arn) would create a cyclic reference.

@whao
Copy link

whao commented Aug 20, 2019

I have the same error with @vertti .

/Users/whao/Developer/MINDeal/mindeal-serverless-dev/node_modules/@aws-cdk/core/lib/private/cfn-reference.ts:108
      throw new Error(`Cross-stack reference (${context.scope.node.path} -> ${this.target.node.path}) has not been assigned a value--call prepare() first`);
            ^
Error: Resolution error: Resolution error: Resolution error: Cross-stack reference (mindeal-apigateway-dev -> mindeal-lambda-stack-dev/test-npm-modules-lambda-dev/Resource) has not been assigned a value--call prepare() first.

@whao
Copy link

whao commented Aug 20, 2019

I tried to exposed lambdas to my DyanmodbStack and it works fine.

@nija-at
Copy link
Contributor

nija-at commented Aug 23, 2019

Able to reproduce this with this CDK code -

#!/usr/bin/env node
import cdk = require('@aws-cdk/core');
import lambda = require('@aws-cdk/aws-lambda');
import apig = require('@aws-cdk/aws-apigateway');

class FirstStack extends cdk.Stack {
    public readonly firstLambda: lambda.Function;

    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
      super(scope, id, props);

      this.firstLambda = new lambda.Function(this, 'firstLambda', {
        code: lambda.Code.asset('resources'),
        handler: 'index.handler',
        runtime: lambda.Runtime.NODEJS_10_X,
      });
    }
}

interface SecondStackProps extends cdk.StackProps {
  readonly lambda: lambda.Function;
}

class SecondStack extends cdk.Stack{
  constructor(scope: cdk.Construct, id: string, props: SecondStackProps) {
    super(scope, id, props);

    const api = new apig.RestApi(this, 'BooksApi');
    api.root.addMethod('ANY');
    const booksApi = api.root.addResource('books');
    const lambdaIntegration = new apig.LambdaIntegration(props.lambda);
    booksApi.addMethod('GET', lambdaIntegration);
  }
}
  
const app = new cdk.App();
const first = new FirstStack(app, 'FirstStack');
new SecondStack(app, 'SecondStack', { lambda: first.firstLambda });
app.synth();

followed by running cdk synth

@nija-at
Copy link
Contributor

nija-at commented Sep 2, 2019

Update: Identified that the bug lies with API Gateway specific implementation of the Prepare phase, specifically within the LatestDeploymentResource.

The bug is here - https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-apigateway/lib/deployment.ts#L131.

The prepare phase, among other things, identifies intra-stack and cross-stack dependencies and registers them, for future resolution. It can be fully resolved only after the prepare phase is complete.

@nija-at nija-at added @aws-cdk/aws-apigateway Related to Amazon API Gateway and removed needs-triage This issue or PR still needs to be triaged. labels Sep 2, 2019
nija-at pushed a commit that referenced this issue Sep 2, 2019
…text

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

fixes #3705
@nija-at
Copy link
Contributor

nija-at commented Sep 4, 2019

Update: I've found the cause and have a fix for this over here - #3906 - but is currently untestable because I've hit the cyclic reference error (#3000).

Working on identifying the root cause for the cyclic reference error.

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
@ghost
Copy link

ghost commented May 29, 2020

Any updates on this?

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.
Projects
None yet
4 participants