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:

  • JSON is easy to break: All languages have a syntax and will get grumpy when you misuse the syntax and JSON is no exception. JSON is a language riddled with commas and encapsulation and when written by humans is very easy to make mistakes and become equally difficult to repair. Some examples include: leaving trailing commas in lists, complexity in quoting every string and the need to escape many special characters.
  • JSON has no syntax for commenting: Complex applications have complex code and there are no unanimous solutions. This behavior develops the need for commenting, which is ultimately the ability to communicate your behaviors to colleagues and your future self.
  • JSON has no native handling of dynamic syntax: Ever wonder why AWS has provided us with so many intrinsic functions like FnJoin, FnAnd, FnEquals and others? It’s because you need fluidity in your template design and JSON can not provide it. It’s that simple, all these odd ways of accomplishing normal behavior is buried in their API documentation.

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:

  • Reduce code duplication with looping
  • Use your own APIs to pull in application configuration
  • Write comments to your teammates and uncover the mysteries of your decisions
  • Leverage the AWS SDK to tailor your infrastructure with dynamic configuration–subnets, regions, availability zones without the complication of Lambda anyone?

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:

  • There’s no need to pass in parameters to CloudFormation for environment information
  • A short comment is present to provide some context to the work going on
  • The brevity of the DSL’s resource declaration is much easier to follow

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
Voiced by Amazon Polly