A golang library for reading and producing CloudFormation templates
Go
Switch branches/tags
Nothing to show
Clone or download
mweagle Merge pull request #23 from mweagle/master
Replace HTML scraper with JSON schema transformation
Latest commit 38e5b66 Jun 4, 2018
Permalink
Failed to load latest commit information.
deploycfn deploycfn: add support for automaticall un-inlining large lambda func… Jan 13, 2017
examples InstancePort values are represented as Strings in the CF template Jun 10, 2017
scraper Include SHA in comment May 25, 2018
.gitignore add tests Nov 29, 2015
.travis.yml update go versions for travis Apr 26, 2017
LICENSE add LICENSE Feb 10, 2017
README.md update readme Apr 4, 2016
bool.go document all the things Nov 29, 2015
bool_test.go Update tests with correct error message Jun 10, 2017
cloudformation.go doc: fix typo Nov 29, 2015
creation_policy.go add CreationPolicy object to resource Mar 15, 2016
custom_resource_test.go Support user-defined CustomResource providers to register with go-clo… Dec 22, 2015
func.go Fn::ImportValue support Oct 1, 2016
func_base64.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_base64_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_findinmap.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_findinmap_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_getatt.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_getatt_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_getazs.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_getazs_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_if.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_importvalue.go PR feedback Oct 7, 2016
func_importvalue_test.go Patch up tests Oct 7, 2016
func_join.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_join_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_ref.go add tests Nov 29, 2015
func_ref_test.go add tests Nov 29, 2015
func_select.go Patch up test Apr 28, 2018
func_select_test.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
func_test.go add tests Nov 29, 2015
iam_policy.go Properly handle single statement IAM policies Nov 29, 2016
iam_policy_test.go Properly handle single statement IAM policies Nov 29, 2016
integer.go Update signature per comments on #6 Jan 17, 2016
integer_test.go Patch up tests Jun 10, 2017
roundtrip_test.go Enable app.template test Jun 10, 2017
schema.go Updated schema for 5/24 release May 25, 2018
schema.json Updated schema for 5/24 release May 25, 2018
schema_gen.go Update scraper to use new script Jun 10, 2017
string.go create interfaces Stringable, StringListable that represent objects r… Jan 8, 2016
string_list.go Add a bit more resiliency for unmarshalling Mar 10, 2018
string_list_test.go update test expectations for string list Aug 12, 2016
string_test.go Update tests with correct error message Jun 10, 2017
template.go Style change Mar 10, 2018
update_policy.go Add UpdatePolicyCodeDeployLambdaAliasUpdate policy entry Jan 11, 2018

README.md

Build Status

This package provides a schema and related functions that allow you to parse and serialize CloudFormation templates in golang. The package places an emphasis on type-safety so that the templates it produces are (slightly) more likely to be correct, and maybe you can avoid endless cycles of UPDATE_ROLLBACK_IN_PROGRESS.

Parsing example:

t := Template{}
json.NewDecoder(os.Stdin).Decode(&t)
fmt.Printf("DNS name: %s\n", t.Parameters["DnsName"].Default) 

Producing Example:

t := NewTemplate()
t.Parameters["DnsName"] = &Parameter{
  Type: "string",
  Default: "example.com",
  Description: "the top level DNS name for the service"
}
t.AddResource("DataBucket", &S3Bucket{
  BucketName: Join("-", String("data"), Ref("DnsName"))
})
json.NewEncoder(os.Stdout).Encoder(t)

See the examples directory for a more complete example of producing a cloudformation template from code.

Producing the Schema

As far as I can tell, AWS do not produce a structured document that describes the CloudFormation schema. The names and types for the various resources and objects are derived from scraping their HTML documentation (see scraper/). It is mostly, but not entirely, complete. I've noticed several inconsistencies in the documentation which suggests that it is constructed by hand. If you run into problems, please submit a bug (or better yet, a pull request).

Object Types

Top level objects in CloudFormation are called resources. They have names like AWS::S3::Bucket and appear as values in the "Resources" mapping. We remove the punctuation and redundant words from the name to derive a golang structure name like S3Bucket.

There are other non-resource structs that are refered to by resources or other non-resource structs. These objects have names with spaces in them, like "Amazon S3 Versioning Configuration". To derive a golang type name the non-letter characters and redundant words are removed to get S3VersioningConfiguration.

Type System

CloudFormation uses three scalar types: string, int and bool. When they appear as properties we represent them as *StringExpr, *IntegerExpr, and *BoolExpr respectively.

type StringExpr struct {
  Func    StringFunc
  Literal string
}

// StringFunc is an interface provided by objects that represent 
// CloudFormation functions that can return a string value.
type StringFunc interface {
  Func
  String() *StringExpr
}

These types reflect that fact that a scalar type could be a literal value ("us-east-1") or a JSON dictionary representing a "function call" ({"Ref": "AWS::Region"}).

Another vagary of the CloudFormation language is that in cases where a list of objects is expected, a single object can provided. For example, AutoScalingLaunchConfiguration has a property BlockDeviceMappings which is a list of AutoScalingBlockDeviceMapping. Valid CloudFormation documents can specify a single AutoScalingBlockDeviceMapping rather than a list. To model this, we use a custom type AutoScalingBlockDeviceMappingList which is just a []AutoScalingBlockDeviceMapping with extra functions attached so that a single items an be unserialized. JSON produced by this package will always be in the list-of-objects form, rather than the single object form.

Known Issues

The cloudformation.String("foo") is cumbersome for scalar literals. On balance, I think it is the best way to handle the vagaries of the CloudFormation syntax, but that doesn't make it less kludgy. A similar approach is taken by aws-sdk-go (and is similarly cumbersome).

There are some types that are not parsed fully and appear as interface{}.

I worked through public template files I could find, making sure the library could accurately serialize and unserialize them. In this process I discovered some of the idiosyncracies described. This package works for our purposes, but I wouldn't be surprised if there are more idiosyncracies hidden in parts of CloudFormation we are not using.

Feedback, bug reports and pull requests are gratefully accepted.