Using a parameter to override a Mapping in Cloudformation
A discussion arose on InfraCoders Slack recently, about whether to use Mapping or Parameters in CloudFormation. I chimed in, and mentioned a pattern that we’re using to leverage Mappings to provide defaults, but still utilise the flexibility of a parameter to override when needed; so I’m sharing the pattern that I mentioned.
Mapping is a useful capability in AWS’s CloudFormation to provide a lookup mechanism for resource parameters. This is particularly useful for parameters such as Instance Types, where you may want to use different sizes or types between environments.
For example, you may want to use T4’s in nonprod and R6’s in production. A Mapping would allow this to be easily achieved in a template, and a mapping resource for this could look like:
Mappings:
EnvAttrs:
RdsNodeType:
dev: db.t4g.medium
sandbox: db.r6g.xlarge
production: db.r6g.12xlarge
To use the map:
Resources:
RDS:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AllowMajorVersionUpgrade: true
AutoMinorVersionUpgrade: true
DBInstanceClass:
- !FindInMap [EnvAttrs, RdsNodeType, !Ref Environment]
This allows the same template to be used across multiple deployment and environments.
Sometimes, however it is useful to change the instance types for experiments … and it’s nice to be able to do those experiments without needing to do a commit.
To accomplish this, we need to leverage the Conditions functionality. Below is an example of a template snippet that uses this pattern:
Parameters:
DBInstanceClass:
Type: String
Default: ""
Environment:
Type: String
Default: "dev"
Mappings:
EnvAttrs:
RdsNodeType:
dev: db.t4g.medium
sandbox: db.r6g.xlarge
production: db.r6g.12xlarge
Conditions:
UseCustomDBInstanceType: !Not [!Equals [!Ref DBInstanceClass, ""]]
Resources:
RDS:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: !If
- UseCustomDBInstanceType
- !Ref DBInstanceClass
- !FindInMap [EnvAttrs, RdsNodeType, !Ref Environment]
If no parameters are provided, then the value from the Map RdsNodeType
will be used; for example if Environment is sandbox
then RdsNodeType
is db.r6g.xlarge
.
However this type can be changed for an experiment by adding a extra parameter when deploying the template. If the parameter DBInstanceClass
is provided, then the condition UseCustomDBInstanceType
will become true
and then the value from the parameter DBInstanceClass
will be used, instead of the value from the EnvAttrs
mapping table.