McShaman
McShaman

Reputation: 3985

Referencing !Ref DynamoDB table name in a AWS CloudFormation template

I am trying to locally test passing the table name of a DynamoDB table as declared in my CloudFormation template file.

From all the documentation I have read, I should be able to reference the the TableName property value of a DynamoDB resource using the !Ref intrinsic function. However when I test this locally the property is undefined.

Consider the following example:

Transform: 'AWS::Serverless-2016-10-31'
Resources:
  ServerlessFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: nodejs10.x
      Handler: index.handler
      Environment: 
        Variables:
          TABLE_NAME: !Ref DynamoDBTable # <- returning undefined
      Events:
        GetCocktails:
          Type: Api
          Properties:
            Path: /
            Method: get
  DynamoDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: DynamoDBTableName
      AttributeDefinitions:
        - AttributeName: ID
          AttributeType: S
      KeySchema:
        - AttributeName: ID
          KeyType: HASH
      ProvisionedThroughput: 
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

I expect the TABLE_NAME environment variable to be DynamoDBTableName however it returns undefined. How do I get the template to work as expected?

Upvotes: 18

Views: 15918

Answers (5)

Nacho
Nacho

Reputation: 119

I was struggling with the same, it looks like you can't access the TableName.

The workaround I'm doing is to call the resource in the tamplate.yml with the same table name...

In template.yml:

Globals:
  Function:
    Runtime: nodejs12.x
    ...
    Environment:
      Variables:
        DYNAMODB_TABLE: !Ref MyDynamoTable
MyDynamoTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: MyDynamoTable
      AttributeDefinitions:
        - AttributeName: PK
          AttributeType: S
        - AttributeName: SK
          AttributeType: S

Then, in my .js component:

const tableName = process.env.DYNAMODB_TABLE;

I hope they solve this soon.... this way is not ideal. Cheers!

Upvotes: 5

Lord of the Goo
Lord of the Goo

Reputation: 1287

As stated by someone else the only attributes exposed by an AWS::DynamoDB::Table are: Arn and StreamArn (See AWS CloudFormation DynamoDB Documentation).

Provided the syntax of the DynamoDB's arns you can retrieve the table name in the following way:

      Environment: 
        Variables:
          TABLE_NAME: !Select [1, !Split ['/', !GetAtt DynamoDBTable.Arn]] 

which will return DynamoDBTableName.

Upvotes: 17

Andrew Kovalenko
Andrew Kovalenko

Reputation: 6710

!Ref returns a name of the resource by "logical name" and should work for your situation. However resource (your table) should exists before you reference it, so you have 2 options:

  • declare you table resource earlier in the template (before you reference it)

  • use DependsOn property on your lambda like

ServerlessFunction:
    Type: AWS::Serverless::Function
    DependsOn: DynamoDBTable

As for using Fn::GetAtt:

Based on AWS Documentation when you create a resource of type AWS::DynamoDB::Table there are only 2 attributes available for Fn::GetAtt:

  • Arn
  • StreamArn

which means there is no way to get TableName attribute for DynamoDB table with Fn::GetAtt in current version of CloudFormation.

Upvotes: 1

ElRuncho
ElRuncho

Reputation: 29

Even though !Ref does return the Logical id of the resource, in this case the DyanmoDB table name, you need to make sure that the resource exist before referencing it.

As far as I can see in your code the function creation is not dependent on the Dynamo table beign created first

ServerlessFunction:
Type: AWS::Serverless::Function
Properties:
  Runtime: nodejs10.x
  Handler: index.handler
  Environment: 
    Variables:
      TABLE_NAME: !Ref DynamoDBTable 
  Events:
    GetCocktails:
      Type: Api
      Properties:
        Path: /
        Method: get

In this case CFN will create resources from top to bottom meaning the lambda function will be created before the DyanoDb table causing the !Ref to be undefined given the fact that the table does not exist yet. You can fix this by adding a dependency on the lambda resource like so:

ServerlessFunction:
DependsOn: DyanamoDBTable # <- will not be created before the dyanmoDB table
Type: AWS::Serverless::Function
Properties:
  Runtime: nodejs10.x
  Handler: index.handler
  Environment: 
    Variables:
      TABLE_NAME: !Ref DynamoDBTable
  Events:
    GetCocktails:
      Type: Api
      Properties:
        Path: /
        Method: get

This will make sure that no matter what, your table is created first and then the !Ref to the resource will not be undefined since the table already exist and can be referenced

Upvotes: -2

Alfonso Ledesma
Alfonso Ledesma

Reputation: 1

The !Ref DynamoDBTable returns the ARN from your resource so, you get your reference response like this:

arn:aws:dynamodb:us-east-1:123456789012:table/testddbstack-myDynamoDBTable-012A1SL7SMP5Q/stream/2015-11-30T20:10:00.000.

Instead you only need to provide the name DynamoDBTableName so, my suggestion is to use !GetAtt CloudFormation intrinsic function and get the name: !GetAtt DynamoDBTable.TableName

Upvotes: -5

Related Questions