Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Working With CFNDSL in AWS CloudFormation

DZone's Guide to

Working With CFNDSL in AWS CloudFormation

CFNDSL is a tool and open source project begging for your contributions to improve and grow. The purpose of the tool is to provide a simple DSL for AWS CloudFormation templating with Ruby. Read on to learn more.

· Cloud Zone
Free Resource

Site24x7 - Full stack It Infrastructure Monitoring from the cloud. Sign up for free trial.

CFNDSL is a tool created by stevenjack and is an open source project begging for your contributions to improve and grow. The purpose of the tool is to provide a simple DSL for AWS CloudFormation templating with Ruby.

If you’re just now joining us I suggest you take a look at the first post in our series about why you should use the DSL.

Using CFNDSL in a Nutshell

Since this tool is written in Ruby and CloudFormation JSON, interacting with the DSL is simply a matter of using identifiers to interact with the API. The workflow for creating CloudFormation templates with CFNDSL is quite succinct–create your Ruby CFNDSL template and then execute the gem on it.

$ cfndsl my-template.rb > my-template.json

Understanding the DSL

Working with the CFNDSL syntax is straightforward once you understand how it’s constructed. If you’re new to Ruby when trying to dive into this it can also make things more difficult—so pay close attention here if that's you.

Below is an example from the project’s readme; let’s dissect it.

CloudFormation {
 Description "Test"

 Parameter("One") {
 String
 Default "Test"
 MaxLength 15
 }

 Output(:One,FnBase64( Ref("One")))

 EC2_Instance(:MyInstance) {
 ImageId "ami-12345678"
 }
}
  1. All identifiers are CamelCase names of the resource property keys in the original JSON schema provided by AWS for CloudFormation. For example, “MaxLength” in the instance declaration is unchanged.
  2. The resource type (e.g. AWS::EC2::Instance) follows a pattern throughout the DSL: "ServiceName_ResourceName"—in this example, EC2_Instance. To elaborate, here’s some more examples:
    1. AWS::AutoScaling::AutoScalingGroup is AutoScaling_AutoScalingGroup
    2. AWS::IAM::InstanceProfile is IAM_InstanceProfile
    3. AWS::Lambda::Function is Lambda_Function
    4. AWS::RDS::DBSecurityGroup is RDS_DBSecurityGroup
  3. Identifiers throughout the DSL are method invocations—so be prepared to supply multiple parameters where needed.

Pro Tip: If you are unsure what properties a resource takes, how to format their identifiers, or which data-type they accept, the project has them all listed nicely in a configuration file located in /lib/cfndsl/aws_types.yaml. This is an invaluable resource when writing templates quickly.

Using AWS Functions

AWS’ CloudFormation comes with some useful syntax for performing various functions while inside the templates. Some examples of this include: string joining, base64 encode, object referencing, and condition functions. You can probably figure that most of these intrinsic functions are mostly unused in CFNDSL since ruby provides this functionality natively, however, they are still made available for use by the DSL.

Let’s take a look at an example we’re all familiar with—adding UserData to an EC2 Instance:

AutoScaling_LaunchConfiguration(:launchConfig) {
 AssociatePublicIpAddress "False"
 IamInstanceProfile Ref(:instanceProfile)
 InstanceType Ref(:instanceType)
 ImageId Ref(:amiID)
 SecurityGroups([
 Ref(:securityGroup)
 ])
 UserData FnBase64(FnFormat(<<EOF,
#!/bin/bash
set -xe

/opt/SomeApplication/bin/some-whacky-script.sh %{param_name}
EOF
 { “param_name” => “bananas” }))
}

There’s quite a few things going on in this example. We’re using an intrinsic function from CloudFormation FnBase64 to encode and a CFNDSL helper function FnFormat to allow us to parameterize the script. In addition to these shown above, there is also support for all the other functions in the DSL, you can check them out on the Ruby docs page.

ProTip: Instead of writing your script directly into the template you should consider loading it in from the filesystem and formatting it appropriately. You can reduce the verbosity of the code this way and prevent duplication when you need to reuse the imported script. I’ll leave it to the reader to make this more elegant, but here’s a one-liner to accomplish it:

FnBase64(FnJoin(‘’, File.read(path).split("\n").map { |line| line + "\n" }))

Another way you can reduce duplication and keep your templates tidy is to extract your IAM Policy Documents into separate files and load them in where needed. Here’s an example:

IAM_Role(:instanceRole) {
 AssumeRolePolicyDocument(eval(File.read(policy_json_path)))
}

In the above snippet, the contents of your role-policy.rb file would simply be the JSON schema of your policy document. Ruby will evaluate that properly at template compile time.

Wrapping it Up

The next time we meet (coming soon), we’ll be discussing some of the advanced features of the tool and I’ll share with you some effective ways to troubleshoot your CloudFormation templates.

Site24x7 - Full stack It Infrastructure Monitoring from the cloud. Sign up for free trial.

Topics:
aws ,amazon ,cloudformation

Published at DZone with permission of Paul Duvall, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}