1

A standard pattern using DynamoDB is to separate data used by each environment by prefixing the table names with any environment-specific string.

I assumed that this would be easy to do using ElasticBeanstalk and the CloudFormation configurations in .ebextensions. However - for my platform (Java 8 running on 64bit Amazon Linux) at least - this seems not to be the case.

My naive implementation was to add an environment property (DB_PREFIX) for each environment and then adapt my table creation config in .ebextensions as follows:

Resources:
  UserTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName:
        Fn::Join:
          - '_'
          - - ${env:DB_PREFIX}
            - 'User'
      KeySchema:
        HashKeyElement: {AttributeName: id, AttributeType: S}
      ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1}

This doesn't work, possibly because, for my platform at least, environment properties are not made available as OS environment variables (see https://stackoverflow.com/a/36567121/96553 ).

I have also thought about conditionally setting an AWS environment property based on the environment name (not a great solution as it doesn't scale well) it might be acceptable.

Does anyone have a pattern that they're already using for this kind of problem?

kichik
  • 33,220
  • 7
  • 94
  • 114
dnh
  • 527
  • 4
  • 15

2 Answers2

3

Simply don't set a name. CloudFormation will select a unique name for you that contains the stack name. Another option is using ${AWS::StackName} yourself.

Resources:
  UserTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName:
        Fn::Sub: ${AWS::StackName}_User
      KeySchema:
        HashKeyElement: {AttributeName: id, AttributeType: S}
      ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1}
kichik
  • 33,220
  • 7
  • 94
  • 114
  • This isn't a perfect solution - I would have preferred table name prefixes that made it easy to understand the environment to which each table relates. However it unblocked me with the task being developed, so thank you for that solution. – dnh May 19 '18 at 17:17
1

Might not be what you're looking for, but instead of relying on cloudformation to handle environment differences, I do so with a very simple build system. Say you have two envrionments, one dev and one prod. My build system will output two entirely different dists:

/dev 
   .ebextensions
/prod
   .ebextensions

In the /dev .ebextensions file of course everything is prefixed with dev-. In /prod .ebextensions, everything is prefixed with prod-. I use gulp and nunjucks to do this, but there are a lot of options out there. So I don't have to worry about how cloudformation handles things, I know that my output is exactly what I want. I can even validate the contents of /dev and /prod with some simple tests.

In your case, you'd get this in the /dev output folder:

Fn::Join:
      - '_'
      - - dev
        - 'User'

and this in /prod:

Fn::Join:
      - '_'
      - - prod
        - 'User'

More details on how I do that: https://stackoverflow.com/a/49011398/3650835

KayakinKoder
  • 3,243
  • 3
  • 23
  • 37