5
votes

Question: what's the best way to have optional resources on a Serverless framework based Lambda?

I want to let Serverless cares about resources that the Lambda needs on lower environments (dev, test, staging), and have independent ones for higher environments, like production.

I was thinking about using something like

resources: 
    Resources: ${file(../${self:provider.stage}-resources.yml)}

my resources yml is like the following:

SQSQueue:
  Type: AWS::SQS::Queue
  Properties:
    QueueName: ${self:service}-${self:provider.stage}-queue

SNSTopic:
  Type: AWS::SNS::Topic
  Properties:
    DisplayName: TEST SNS Topic
    TopicName: ${self:service}-${self:provider.stage}-topic

SNSSubscription:
  Type: AWS::SNS::Subscription
  Properties:
      Endpoint: [email protected]
      Protocol: email
      TopicArn: { "Fn::Join" : ["", ["arn:aws:sns:${self:provider.region}:", { "Ref" : "AWS::AccountId" }, ":${self:resources.Resources.SNSTopic.Properties.TopicName}" ] ]  }

But it's not working. Any ideas on what's the best practice to achieve that?

2
that seems to be right, I'm doing something similar. Did the cloudformation stack json added your variables? could you share the structure of one of your stage-resource.yml? - dege
What's inside your *-resources.yml file? - Noel Llevares
@dege I've updated my questions with some more info. The problem is, when I try to deploy it like that, it get stucked, doing anything. - abierto
sorry @abierto can't see the problem, by any chance are you trying to access a file with the wrong path? did you tried setting up a custom variable on your serverless.yml and used before going to external file? - dege
@dege as I can see, if I only load the queue and the topic everything is fine. When I try to also load the subscription, it's not working. - abierto

2 Answers

5
votes

The description in the question focuses on getting all resources in a single resource file, and use different such files per stage. This works, but has the limitation that you must put at least one resource in each stage. And also forces you to group together resources.

Another way to include optional resources that I used in serverless.yml is as follows:

provider:
  name: aws
  stage: ${opt:stage, 'dev'}

resources:
  - ${file(./sls-resources/mandatory-resource.yml)}
  - ${file(./sls-resources/optional-resource.${self:provider.stage}.yml), ''}

Then, you only create optional-resource.prod.yml to hold your production-only resource. When generating the template for dev stage, serverless resolves the optional reference to an empty element because the file does not exist, and then just ignores it.

Note I used the stage variable just as example, but it can be any other variable, e.g. region or a custom variable.

2
votes

Replacing this:

TopicArn: { "Fn::Join" : ["", ["arn:aws:sns:${self:provider.region}:", { "Ref" : "AWS::AccountId" }, ":${self:resources.Resources.SNSTopic.Properties.TopicName}" ] ]  

with this:

TopicArn: {"Ref" : "SNSTopic"}

Fixed my issue.