Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mathematical operations in CloudFormation

Is it possible to perform some sort of mathematical operation in a CloudFormation template?

There are two areas that I've encountered where this would be useful:

  1. Setting IOPS which needs to be a ratio of the disk size.
  2. Setting CloudWatch Alarms for RDS Free Storage Space. It would be useful to set this as a % of the disk size.
like image 974
Hardik Kamdar Avatar asked Jan 09 '16 12:01

Hardik Kamdar


3 Answers

There are two general solutions to performing custom logic in CloudFormation templates not supported by Intrinsic Functions, such as mathematical operations:

1. Custom Resource

Write a Custom Resource to execute your mathematical operation, passing inputs as Properties and outputs as Values. Here's a self-contained working example that returns Result: 13 as a Stack Output:

Launch Stack

Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: "/"
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  AddFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          exports.handler = function(event, context) {
            var result = parseInt(event.ResourceProperties.Op1) + parseInt(event.ResourceProperties.Op2);
            response.send(event, context, response.SUCCESS, {Value: result});
          };
      Runtime: nodejs
  AddTest:
    Type: Custom::Add
    Properties:
      ServiceToken: !GetAtt AddFunction.Arn
      Op1: 8
      Op2: 5
Outputs:
  Result:
    Description: Result
    Value: !GetAtt AddTest.Value

2. Template Preprocessor

Use a full-featured templating language/platform of your choice to write a 'source' template that produces a valid CloudFormation-template as output. You can use a full-featured CloudFormation-specific library like troposphere, but it's also easy enough to write a simple preprocessor layer to suit your use-case and programming-language/library preferences.

My current choice is embedded Ruby (ERB), mostly because I'm already familiar with it. Here's an example template.yml.erb file using embedded Ruby syntax to perform a mathematical operation that returns Result: 13 as a Stack Output:

Resources:
  # CloudFormation stacks require at least one resource
  Dummy:
    Type: AWS::SNS::Topic
Outputs:
  Result:
    Description: Result
    Value: <%= 8 + 5 %>

To process the template, run cat template.yml.erb | ruby -rerb -e "puts ERB.new(ARGF.read, nil, '-').result" > template.yml, which will write the following CloudFormation-ready template to template.yml:

Resources:
  # CloudFormation stacks require at least one resource
  Dummy:
    Type: AWS::SNS::Topic
Outputs:
  Result:
    Description: Result
    Value: 13
like image 165
wjordan Avatar answered Oct 19 '22 16:10

wjordan


Much later in 2022...

This is one reason for using CDK, which provides a code wrapper (e.g. Javascript, Typescript etc.) over CloudFormation and makes calculations, conditionals sharing etc. much simpler than is possible when only using CloudFormation templates.

like image 2
Steve Chambers Avatar answered Oct 19 '22 16:10

Steve Chambers


Is it still a hack if you limit the range of the StartingValue?

Parameters:
  StartingValue:
    MinValue: 0
    MaxValue: 7
    Type: Number
Outputs:
  MinusOne:
    Value: !Select [ !Ref StartingValue, ["-1","0","1","2","3","4","5","6"] ]
  PlusOne:
    Value: !Select [ !Ref StartingValue, ["1","2","3","4","5","6","7","8"] ]
  TimesTwo:
    Value: !Select [ !Ref StartingValue, ["0","2","4","6","8","10","12","14"] ] 

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-select.html

like image 1
Ryan Williams Avatar answered Oct 19 '22 14:10

Ryan Williams