Conditional serverless.yml based on stage?

I need to make it so a certain scheduled events do not run unless they are running on our prod stage. Is there any syntax that cam be used in serverless.yml to make it so it automatically checks this when running. For instance something like

enabled : ${opt:stage == prod}

Thanks!

2 Likes

Conditional logic isn’t supported.

If you know all of the environments you’re deploying to then you could do something like:

custom:
  enabled:
    dev: false
    prod: true

enabled: ${self:custom.enabled.${opt:stage, self:provider.stage}}
9 Likes

Fantastic! Not conditional, but that works great for our case as we have 3 set stage names. Thanks for the help!

@buggy @DJHoltkamp you can totally do conditions in serverless .yml, and mappings too!

resources:
  Mappings:
    config:
      global:
        key: value
      dev:
        AuroraInstanceSize: db.t2.small
      test:
        AuroraInstanceSize: db.t2.small
      qa:
        AuroraInstanceSize: db.t2.small
      prod:
        AuroraInstanceSize: db.t2.medium
      

  Conditions:
    IsProd:
      Fn::Equals:
        - ${opt:stage}
        - prod  

   Resources:
      SomeIAMRole:
         Type: AWS::IAM::Role
         Condition: IsProd
         Properties:
            etc
            etc
3 Likes

@ezeeetm You can simulate conditional logic in serverless.yml by placing the stage name into the path for a variable then defining the value for every possible stage. I’ve written about that many times including the solution I provided here. It’s good enough for most people but it’s not the same as IF x THEN y ELSE z conditional logic.

CloudFormation is more flexible but it only helps you if you need the conditional logic in the CloudFormation template generated by Serverless. If you need the conditional logic as part of running the Serverless command (for example the plugins to include) then you need to use the stage in the path trick.

Building on the solution by @buggy. If you don’t know all the environments you will be deploying to you could do something like this:

custom:
  enabled:
    dev: true
    prod: true
    other: false

enabled: ${self:custom.enabled.${opt:stage}, self.enabled.other}

So the other stage become all other stages apart from dev and prod

1 Like

Perfect, just what I was looking for :+1:

I was responding more to this. Cloudformation conditional logic is supported, and (as you say) a bit more flexible than the variable replacement provided by sls. I follow a ‘write once run everywhere’ highly parameterized pattern for my infrastructure code, so sometimes I have 30 or more params for a given stack…cfn mappings and conditions are really the best way to handle that kind of parameterizations.

to be fair, I came to sls from many years of cfn, so I view sls more as a tool for making it easier to work with cfn, while others who came to sls first might just look at cfn as ‘the poo that sls spits out’, and prefer to stay in native sls as much as possible, which makes sense.

1 Like

@alechewitt
Not sure what is happening in your example…

Is the “self.enabled.other” part a typo?
Should it not be…
"${self:custom.enabled.other}"

also… I didn’t know it was legit to set vars outside of “custom”?

@iDVB apologies for the late reply.

I was writing out the case where you want dev and prod to be enabled but all other stages to be disabled.

With your configuration looking something like this:

custom:
  enabled:
    dev: true
    prod: true
    other: false

enabled: ${self:custom.enabled.${opt:stage}, self.enabled.other}

If you deployed to a stage called uat then self:custom.enabled.${opt:stage} gets evaluated as self:custom.enabled.uat which does not exist. Therefore it will use the default value of self.enabled.other, which is false.

I wrote it like this because in some situations you might not know all the different stages you are going to be deploying to ahead of time. Therefore you can fallback onto a default value.

As always with Serverless the biggest problem here is that there is zero documentation. I really wish they’d do more to document their tool, its all guess-work and trying to infer syntax from CloudFormation docs. My company chose in their wisdom to use Serverless and everything is an utter nightmare.

3 Likes

This was helpful, as I was looking for this kind of thing as well. I’d agree that for a lot of uses, the solution of having settings for each stage in the custom section is the way to go. But, I needed to conditional a ton of stuff in the resources section. I just wanted to add a small bit to what @ezeeetm’s example provides.

When you create the named condition in the Conditions section of resources, you then need to specify that named condition for each resource you want to condition. Here’s an example:

resources:
  Conditions:
    # Only create the VPC setup in the dev account/stage
    CreateVPCResources:
      Fn::Equals:
        - ${self:provider.stage}
        - dev
  Resources:
    MyVPC:
      Type: AWS::EC2::VPC
      Condition: CreateVPCResources
      Properties:
        CidrBlock: 10.0.0.0/16

Any resources in there that don’t specify that Condition: ... attribute will of course not be affected. More info can be found in the CloudFormation docs for Conditions.

1 Like

I think @iDVB was wondering about the syntax for the self.enabled.other. I think it should be self:custom.enabled.other, otherwise self is referring to the top-level attribute.

1 Like

@alechewitt @ezeeetm What if I need to do logical NOT of the variable. For ex: NOT OF ${self.custom.disabled} . Please suggest

you guys are great thank you for your replies this helped me pretty much

you guys are great. Thank you for your replies this helped me pretty much
snaptube vidmate

You can use serverless-plugin-utils fn:ternary

enabled : ${ternary(opt:stage, ‘prod’, true, false)}