aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.55k stars 3.87k forks source link

(@aws-cdk/aws-lambda-event-sources): DynamoDB Streams must be enabled on the table when already enabled #14046

Closed dkaksl closed 3 years ago

dkaksl commented 3 years ago

Creating a DynamoDB table in one stack, then using it as a lambda's DynamoEventSource in another stack gives the error "DynamoDB Streams must be enabled on the table", even though DynamoDB streams are enabled on the table in the original stack.

Reproduction Steps

In one stack:

import * as dynamodb from '@aws-cdk/aws-dynamodb'

// ...

new dynamodb.Table(this, 'Table', {
      tableName: 'db-stream-sample-table',
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
    })

In another stack:

import * as dynamodb from '@aws-cdk/aws-dynamodb'
import { DynamoEventSource } from '@aws-cdk/aws-lambda-event-sources'

// ...

const existingTable = dynamodb.Table.fromTableName(
      this,
      'existing-table',
      'db-stream-sample-table',
    )

myFunction.addEventSource(
      new DynamoEventSource(existingTable, {
        startingPosition: lambda.StartingPosition.TRIM_HORIZON,
        batchSize: 5,
        bisectBatchOnError: true,
        retryAttempts: 10,
      }),
    )

What did you expect to happen?

To be able to diff and deploy the stack with the DynamoEventSource.

What actually happened?

$ cdk diff
DynamoDB Streams must be enabled on the table <your table here>
Subprocess exited with error 1

Environment


This is :bug: Bug Report

RomainMuller commented 3 years ago

Using Table.fromTableName is the same as using Table.fromTableAttributes, specifying only the table name... In order to support existing streams when importing a table, you have to use the Table.fromTableAttributes API ans specify the table stream ARN.

Are the two stacks part of the same CDK App? If so - you could perhaps pass the table instance across instead of actually manually importing it... This way you would have the stream configuration coming with the table instance naturally...

If you cannot do this, I would suggest storing the table's stream ARN in an SSM Parameter, and retrieving it from there in the second stack.

github-actions[bot] commented 3 years ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

dkaksl commented 3 years ago

@RomainMuller my workaround was to set the stream arn as an output

new cdk.CfnOutput(this, 'table-stream-arn-output', {
      exportName: 'tableStreamArn',
      value: tableStreamArn,
    })

and grabbing it with Fn.importValue

const tableStreamArn = Fn.importValue('tableStreamArn')

and using L1 construct to create the event source

new lambda.CfnEventSourceMapping(
      this,
      'dynamo-event-source',
      {
        eventSourceArn: tableStreamArn,
        functionName: myFunction.functionArn,
        startingPosition: 'TRIM_HORIZON',
      },
    )

But I guess if I have the stream ARN, I can use Table.fromTableAttributes like you suggest and avoid using the L1 constructs.

dkaksl commented 3 years ago

@RomainMuller update: Yes, it worked fine when using Table.fromTableAttribues. Got rid of the L1 construct.

But I'm not convinced. Seems like a flaw that I would have to know an ARN that comes from the dynamodb resource I am referencing (and importing). I'd maybe not go as far as calling that a bug, but it's counter-intuitive and IMHO it would be better if the resource just had that information (which, if I look in the management console, it does).