Stelligent

Taking CloudFormation to the next level with CFNDSL

Everybody loves AWS CloudFormation. It’s a powerful configuration management tool to provision and manage resources in your AWS account in code. In 2011, when CloudFormation was released there was much rejoicing from DevOps personnel around the world, however, one simple thing has made it a painful tool to adopt and use efficiently: JSON.
JSON overall is a fantastic tool for representing objects as code, it’s easily readable by humans, it can handle various data types and it’s a well known and widely accepted syntax.
When approaching a tool with the complexity and power of CloudFormation you expect your interface with the configuration to be natural, quick and ultimately maintainable. JSON as a choice for a configuration management tool leaves much to be desired in these areas:

What if I told you, you could create expressive, dynamic and documented CloudFormation templates in ruby?
CFNDSL, a tool originally created by Chris Howe was created to address these concerns and more. Using this DSL is as simple as writing some ruby code — a scripting language that many are familiar with and if not, it’s quick to learn.
You can get started with CFNDSL as quickly as sudo gem install cfndsl and begin using expressive syntax and have access to essentially any resource you can imagine to tailor your infrastructure to your needs:

Let’s make a quick comparison on two templates, one in CloudFormation’s natural form and the same template written in ruby with CFNDSL. For the example, we want to only create a EC2::Volume resource when the environment we’re creating is meant for production use.
CloudFormation JSON using Conditions

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Parameters" : {
    "EnvType" : {
      "Description" : "Environment type.",
      "Default" : "test",
      "Type" : "String",
      "AllowedValues" : ["prod", "dev", "test"],
      "ConstraintDescription" : "must specify prod, dev, or test."
    }
  },
  "Conditions" : {
    "CreateProdResources" : {"Fn::Equals" : [{"Ref" : "EnvType"}, "prod"]},
  },
  "Resources" : {
    "NewVolume" : {
      "Type" : "AWS::EC2::Volume",
      "Condition" : "CreateProdResources",
      "Properties" : {
        "Size" : "100",
        "AvailabilityZone" : { "Fn::GetAtt" : [ "EC2Instance", "AvailabilityZone" ]}
      }
    }
  }
}

CFNDSL using control structures

CloudFormation {
    Description "A simple example."
    # We only need an extra volume created in our production environment
    if environment == :production
        EC2_Volume {
            Size 100
            AvailabilityZone "us-east-1a"
        }
    end
}

The results are clear, the CFNDSL version provides us many immediate benefits even with a small example:

You can’t always replace the CloudFormation syntax for conditions with ruby. However, based on when you need that decision to occur, the source of your conditions and where in the pipeline you compile your template, you will be able to reduce the verbosity significantly.
Have I sold you yet? Check out the repository on Github, dive in and write expressive CloudFormation templates today.


This was part one of our series: be sure to read parts two and three!

Stelligent Amazon Pollycast