Automatic CloudFormation Template Validation with Guard::CloudFormation
One of the nice little conveniences I’ve started to use in my daily work with Amazon Webservices CloudFormation is the Guard::CloudFormation ruby gem.
The Guard gem "is a command line tool to easily handle events on file system modifications" which, simply put, means “run a command when a file changes”. While I’ve used a number of different little tools to do this in the past, Guard presents a promising base to build more specific test executors on so I’ve started to integrate it in to more aspects of my work flow. In this example I’m going to show you how to validate a CloudFormation template each time you save a change to it.
The example below assumes that you already have the AWS CloudFormation command line tools installed, configured and available on your path.
# our example, one resource, template.
$ cat example-sns-email-topic.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description" : "Creates an example SNS topic",
"Parameters" : {
"AutoScaleSNSTopic": {
"Description": "Email address for notifications.",
"Type": "String",
"Default": "testymctest@example.org"
}
},
"Resources" : {
"EmailSNSTopic": {
"Type" : "AWS::SNS::Topic",
"Properties" : {
"DisplayName" : "Autoscaling notifications for Location service",
"Subscription": [ {
"Endpoint" : { "Ref" : "AutoScaleSNSTopic" },
"Protocol" : "email"
} ]
}
}
}
}
# now, do a manual run to ensure all the basics are working
$ cfn-validate-template --template-file example-sns-email-topic.json
PARAMETERS AutoScaleSNSTopic testymctest@example.org false Email address for notifications.
Now that we have confirmed our CloudFormation tools are working we can sprinkle some automation all over it.
# install the required gems
gem install guard guard-cloudformation
# and then create a basic Guardfile
# in this case we watch all .json files in the current directory
cat << 'EOC' > Guardfile
guard "cloudformation", :templates_path => ".", :all_on_start => false do
watch(%r{.+\.json$})
end
EOC
# run guard
$ guard
10:07:49 - INFO - Guard is using NotifySend to send notifications.
10:07:49 - INFO - Guard is using TerminalTitle to send notifications.
10:07:49 - INFO - Guard is now watching at '/home/cfntest/.../cloudformations/location'
[1] guard(main)>
Now that guard
is up and running open up a second terminal
to the directory you’ve been working in. We’ll now make a couple of
changes and watch Guard in action. First we’ll make a small change to the text that shouldn’t break anything.
# run the sed command to change the email address - shouldn't break
$ sed -i -e 's/testymctest@example.org/test@example.org/' example-sns-email-topic.json
# in the term running Guard we see -
10:12:31 - INFO - Validating: example-sns-email-topic.json
Validating example-sns-email-topic.json...
PARAMETERS AutoScaleSNSTopic test@example.org false Email address for notifications.
On my desktop the validation output is a lovely terminal green and I also get a little pop-up in the corner telling me the validate was successful. Leaving Guard open, we’ll run a breaking change.
# run the sed command to remove needed quotes - this will not end well
$ sed -i -e 's/"Ref" :/Ref :/' example-sns-email-topic.json
# in the term running Guard we see -
10:13:51 - INFO - Validating: example-sns-email-topic.json
Validating example-sns-email-topic.json...
cfn-validate-template: Malformed input-Template format error: JSON not well-formed. (line 19, column
27)
Usage:
cfn-validate-template
[--template-file value ] [--template-url value ] [General Options]
For more information and a full list of options, run "cfn-validate-template --help"
FAILED: example-sns-email-topic.json
The ‘FAILED: example-sns-email-topic.json’ line is displayed in less welcome red, the dialog box pops up again and we know that our last change was incorrect. While this isn’t quite as nice as having vim running the validate in the background and taking you directly to the erroring line it’s a lot easier to plumb in to your tool chain and gives you 80% of the benefit for very little effort. For completeness we’ll reverse our last edit to fix the template.
# sed command to fix the template
$ sed -i -e 's/Ref :/"Ref" :/' example-sns-email-topic.json
# in the term running Guard we see -
10:22:42 - INFO - Validating: example-sns-email-topic.json
Validating example-sns-email-topic.json...
PARAMETERS AutoScaleSNSTopic test@example.org false Email address for notifications.
One last config option that’s worth noting is ':all_on_start => false'
from the Guardfile. If this is set to true then, as you’d
expect by the name, all CloudFormation templates that match the
watch will be validated when Guard starts. I find the validates to be
quite slow and I often only dip in to a couple of templates so I set
this to off. If you spend more focused time working on nothing but
templates then having this set to ‘true’ gives you a nice early warning in
case someone checked in a broken template. Although your git
hooks shouldn’t allow this anyway. But that’s a different post.
After reading through the validate errors of a couple of days work it seems my most common issue is from continuation commas. It’s just a shame that CloudFormation doesn’t allow trailing commas everywhere.