Conditionally deploying parts of your CloudFormation stack with the Serverless Framework

 

While working on putting the finishing touches on v1 of Hook Relay, we decided to try using AWS Timestream, AWS' recently-released time series database. This led to a problem with deploying our stack, since we are using the Serverless Framework to deploy the Lambda functions we are using to multiple AWS regions.

The problem was that Timestream isn't yet available in all the regions we are using, so the CloudFormation stack that is being generated by the framework isn't valid in those regions that don't have Timestream. There isn't a built-in way to exclude a portion of the resources block (the portion that creates the Timestream database and table) when deploying to specific regions, so we had to get a little creative. Here's our solution:

serverless.yml

service: hook-relay

provider:
  name: aws

custom:
  resources:
    us-east-1: ${file(./resources/timestream.yml)}

resources:
  - ${file(./resources/main.yml)}
  - ${self:custom.resources.${self:provider.region}, ''}

resources/timestream.yml

Resources:
  tsdb:
    Type: AWS::Timestream::Database
    Properties:
      DatabaseName: "hook-relay-${self:custom.stage}"

  tsdeliveries:
    Type: AWS::Timestream::Table
    Properties:
      DatabaseName: !Ref tsdb
      TableName: deliveries

As you can see, we use a combination of custom variables, file includes, default values, and the ability to define multiple Resources blocks to get what we want. First we define a custom variable resources.us-east-1 that yanks in the content of the timestream.yml file, which has the CloudFormation definition of the resources that should only be created in that one region. Then we include the contents of that variable in the resources block by interpolating the current region as part of the variable name, with an empty string as the default fallback when that custom variable doesn't exist (e.g., when deploying to eu-central-1 via a command line option to sls deploy). Finally, we include the contents of resources/main.yml in the resources block. This file has another CloudFormation configuration that defines the resources that should be present in each region, such as DynamoDB tables, SQS queues, etc.

With that, whenever you run sls deploy, regardless of the region you deploy to, you'll get the AWS resources you want, without the ones you don't. Thanks to Cameron Childress for providing essential tips that led to this solution.

Get the Honeybadger newsletter

Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo
    Benjamin Curtis

    Ben has been developing web apps and building startups since '99, and fell in love with Ruby and Rails in 2005. Before co-founding Honeybadger, he launched a couple of his own startups: Catch the Best, to help companies manage the hiring process, and RailsKits, to help Rails developers get a jump start on their projects. Ben's role at Honeybadger ranges from bare-metal to front-end... he keeps the server lights blinking happily, builds a lot of the back-end Rails code, and dips his toes into the front-end code from time to time. When he's not working, Ben likes to hang out with his wife and kids, ride his road bike, and of course hack on open source projects. :)

    More articles by Benjamin Curtis
    An advertisement for Honeybadger that reads 'Turn your logs into events.'

    "Splunk-like querying without having to sell my kidneys? nice"

    That’s a direct quote from someone who just saw Honeybadger Insights. It’s a bit like Papertrail or DataDog—but with just the good parts and a reasonable price tag.

    Best of all, Insights logging is available on our free tier as part of a comprehensive monitoring suite including error tracking, uptime monitoring, status pages, and more.

    Start logging for FREE
    Simple 5-minute setup — No credit card required