Evaluating variables in included variable files

When including variables in your serverless.yml from another yml file, one does this: ${file(…/path/to/env.yml)}
All good there.
However, in my env file (path/to/env.yml), can I again use variables expressions and have them evaluated in the context of my serverless.yml?

Here’s the use case:

  • I reference a lot of CF variables (Dynamo tables, SNS topics, etc.) which are all created in a resources stack.
  • I have a micro services architecture, where each endpoint entity (/users, /products, etc) is it’s own stack, all rolled into a single custom domain with base path mappings in AWS APIG
  • In each of my stacks I need to refer to CF output to generate variable values
  • Rather than put ${cf:resources-stack:variable} in every serverless.yml, I’d like to put them all in one yml file, then reference that in each of my micro stacks
  • When I do this, deploy dies just before the Serverless: Invoke deploy step

For example:
My env.dev.yml might look like this:

PRODUCTS_TABLE: ${cf:${self:custom.stacks.resources}.ProductsTable}
USERS_TABLE: ${cf:${self:custom.stacks.resources}.UsersTable}

serverless.yml for products micro service looks like this:

service: api-products
custom:
  stacks:
    resources: api-resources-${self:provider.stage}
  env: ${file(../env/.env.${self:provider.stage}.yml)}

provider:
  name: aws
  runtime: nodejs8.10
  environment:
    PRODUCTS_TABLE: ${self:custom.env.PRODUCTS_TABLE}
    USERS_TABLE: ${self:custom.env.USERS_TABLE}
functions:
  get-product:
    handler: get-product.handle
    events:
      - http:
          path: /{product_id}
          method: get
          cors: true
          request:
            parameters:
              paths:
                product_id: true

So you can see that .env.dev.yml is included into the custom vars of the serverless.yml, so that I can quickly reference variables from it in my functions. .env.dev.yml is also referencing variables in the serverless.yml it’s included in (this is a bit like how PHP variables work). However, it doesn’t appear as though variables in an included yml will be evaluated where they contain expressions, and not just static values. And even if they were evaluated, would they see the variables they’re referencing in the parent serverless.yml?

Any thoughts/help? How are others with lots of micro services managing variables across their stacks?

Think I answered my own question…

This works perfectly well… to a point. That point is when the variables are circular.
In your included file, don’t reference variables in your included file! Assign them another way.
e.g. I did this:

serverless.yml

custom:
  file: ${file(../path/to/.env.${self:provider.stage}.yml)}

.env.dev.yml

AWS_ACCOUNT_ID: 123456789
PRODUCTS_TABLE: ${cf:${self:custom.stacks.resources}.ProductsTable}
USERS_TABLE: ${cf:${self:custom.stacks.resources}.UsersTable}
IAM_ROLE: arn:aws:iam::${self:custom.file.AWS_ACCOUT_ID}:role/${cf:${self:custom.stacks.resources}.DefaultRole}

That IAM_ROLE variable is referencing - via. the serverless.yml - the same AWS_ACCOUNT_ID in the file. Serverless won’t deploy with this, but also doesn’t show an error.

If you need that circular reference, try this instead:

serverless.yml

custom:
  awsAccountId: ${file(../path/to/.env.${self:provider.stage}.yml):AWS_ACCOUNT_ID}
  file: ${file(../path/to/.env.${self:provider.stage}.yml)}

.env.dev.yml

AWS_ACCOUNT_ID: 123456789
PRODUCTS_TABLE: ${cf:${self:custom.stacks.resources}.ProductsTable}
USERS_TABLE: ${cf:${self:custom.stacks.resources}.UsersTable}
IAM_ROLE: arn:aws:iam::${self:custom.awsAccountId}:role/${cf:${self:custom.stacks.resources}.DefaultRole}