Serverless-offline: Support for environment variables that are defined as CF references

Created on 22 Feb 2017  路  8Comments  路  Source: dherault/serverless-offline

Description

Since Serverless 1.x it is possible to use CloudFormation references as values for environment variables directly. This is very handy, if you for example create a DynamoDB table in your stack with an automatically generated name to support "Replacement" changes with the resource.

So you specify:

environment:
  MY_DB_TABLE_NAME:
    Ref: MyDbTable

...

resources:
  Resources:
    MyDbTable
      Type: AWS::DynamoDB::Table
      Properties:
        ...

Of course this approach also works for arbitrary resource references that return any string like ARNs, names, and many more.

Problem

The offline plugin does not resolve the reference, but initializes MY_DB_TABLE_NAME with { Ref: MyDbTable }

Solution

A possible solution would be, that the offline plugin recognizes that the environment variable content is a CF reference and uses the CloudFormation API (aws-sdk) to resolve it.

For very early development stages where resources are not yet deployed at all, it came to my mind, that an additional useful feature in this context would be that the plugin loads an optional offline.env JSON file that adds the possibility to define offline environment variable overrides for given variables.

enhancement help wanted

Most helpful comment

There is no solution for this or workaround?

As a workaround I've been using serverless variables, which allow for a default value. So I first store the cloudformation reference in a temporary variable, I then use that variable as the default value in for another variable - if an environment variable isn't present:

custom:
  cognitoUserPoolIdFromRef:
    Ref: UserPool
  cognitoUserPoolId: ${env:COGNITO_USER_POOL_ID, self:custom.cognitoUserPoolIdFromRef}


functions:
  api:
    environment:
      COGNITO_USER_POOL_ID: ${self:custom.cognitoUserPoolId}
    handler: dist/lambda/api.handler
    timeout: 60
    events:
      - http: 'ANY api/{proxy+}'

Then my development value for that environment variable is stored in a .env file:

COGNITO_USER_POOL_ID=some-value-here-for-development

And I use the npm module dotenv to load the variable via an npm script:

// inside package.json

"scripts": {
  "dev": "node -r dotenv/config node_modules/serverless/bin/serverless offline start"
}

It's not ideal but works in lieu of a proper solution.

All 8 comments

@HyperBrain I came across this issue yesterday as well, in my case it was for SQS.

A temporary 'fix' was to comment out the environment variable in the serverless config, then set the variable when running sls offline. E.g.

$ MY_DB_TABLE_NAME="example" ./node_modules/.bin/sls offline

Keen to have a solution for this developed though.

Also a problem for references of ${self} for example

provider: stage: dev # ... environment: RDS_USERS_TABLE: 'users_${self:provider.stage}'

There is no solution for this or workaround?

Not yet, a PR would be welcome.

I'm not really familiar with the template system but if you guide me I can make that PR. Where I should began?

There is no solution for this or workaround?

As a workaround I've been using serverless variables, which allow for a default value. So I first store the cloudformation reference in a temporary variable, I then use that variable as the default value in for another variable - if an environment variable isn't present:

custom:
  cognitoUserPoolIdFromRef:
    Ref: UserPool
  cognitoUserPoolId: ${env:COGNITO_USER_POOL_ID, self:custom.cognitoUserPoolIdFromRef}


functions:
  api:
    environment:
      COGNITO_USER_POOL_ID: ${self:custom.cognitoUserPoolId}
    handler: dist/lambda/api.handler
    timeout: 60
    events:
      - http: 'ANY api/{proxy+}'

Then my development value for that environment variable is stored in a .env file:

COGNITO_USER_POOL_ID=some-value-here-for-development

And I use the npm module dotenv to load the variable via an npm script:

// inside package.json

"scripts": {
  "dev": "node -r dotenv/config node_modules/serverless/bin/serverless offline start"
}

It's not ideal but works in lieu of a proper solution.

I think that at least serverless-offline should replace non-string environment variables with undefined in process.env. Right now the whole object is just stuffed in process.env.var which messes up TypeScript among other things.

As a workaround you can introduce a switching mechanism in your .yml file like so:

mySwitch:
  true:
    MY_VAR: 1 #If running offline, get it locally
  false:
    MY_VAR: !Ref FooBar #If not running offline, get it from CF

provider:
  environment:
    MY_VAR: ${self:custom.mySwitch.${env:IS_OFFLINE}.MY_VAR}

Was this page helpful?
0 / 5 - 0 ratings