GoFormation generates GO structures out of the CloudFormation Resource specification.
This specification includes all information, also the link to documentation about AWS Resources.
For a DynamoDB Table - Attribute Definition this would be the Table:
"AWS::DynamoDB::Table": {
"Attributes": {
"Arn": {
"PrimitiveType": "String"
},
"StreamArn": {
"PrimitiveType": "String"
}
},
...
"Properties": {
"AttributeDefinitions": {
"Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-attributedef",
"DuplicatesAllowed": true,
"ItemType": "AttributeDefinition",
"Required": false,
"Type": "List",
"UpdateType": "Conditional"
},
...
And the AttributeDefinition:
"AWS::DynamoDB::Table.AttributeDefinition": {
"Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-attributedef.html",
"Properties": {
"AttributeName": {
"Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-attributedef.html#cfn-dynamodb-attributedef-attributename",
"PrimitiveType": "String",
"Required": true,
"UpdateType": "Mutable"
},
"AttributeType": {
"Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-attributedef.html#cfn-dynamodb-attributedef-attributename-attributetype",
"PrimitiveType": "String",
"Required": true,
"UpdateType": "Mutable"
}
}
},
With that information the generation process:
git clone https://github.com/awslabs/goformation.git
cd goformation
go generate
can generate all GO structures. That means, you can support CloudFormation types immediately. This is a similiar process in CDK Cfnxxx types.
This Table struct is generated in goformation/cloudformation/dynamodb/aws-dynamodb-table.go:
type Table struct {
// AttributeDefinitions AWS CloudFormation Property
// Required: false
// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-attributedef
AttributeDefinitions []Table_AttributeDefinition `json:"AttributeDefinitions,omitempty"`
With that generated structures you may modell CloudFormation in the go program:
template := cloudformation.NewTemplate()
template.Resources["simpletable"] = &dynamodb.Table{
AttributeDefinitions: []dynamodb.Table_AttributeDefinition{
{
AttributeName: "Username",
AttributeType: "S",
},
},
Now I create a DynamoDB Table in goformation:
See infrastructure-as-go/goformation/dynamodb/usertable.go in go-on-aws git.
15 template := cloudformation.NewTemplate()
The template stucture holds all information about the template itself.
16 template.Resources["simpletable"] = &dynamodb.Table{
17 AttributeDefinitions: []dynamodb.Table_AttributeDefinition{
18 {
19 AttributeName: "Username",
20 AttributeType: "S",
21 },
22 },
Resources is just a map[string]Resource, so we identify the Table with its logical name. When CloudFormation creates an instance of the Table, the ID of the instance is called the physical name.
Inside goformation you can now reference this table e.g. with GetAtt which is defined as:
func GetAtt(logicalName string, attribute string) string
43 y, err := template.YAML()
44 if err != nil {
45 fmt.Printf("Failed to generate YAML: %s\n", err)
46 return nil, err
47 }
In CDK the abstraction level is higher. That means you need less lines of code, but you give up some control:
table := dynamodb.NewTable(this, aws.String("table"), &dynamodb.TableProps{
PartitionKey: &dynamodb.Attribute{
Name: aws.String("username"),
Type: dynamodb.AttributeType_STRING,
},
...
})
vs
template.Resources["simpletable"] = &dynamodb.Table{
AttributeDefinitions: []dynamodb.Table_AttributeDefinition{
{
AttributeName: "Username",
AttributeType: "S",
},
},
KeySchema: []dynamodb.Table_KeySchema{
{
AttributeName: "Username",
KeyType: "HASH",
},
},
But you get more control. As of now (dec 2021) the table class is not yet available in CDK. With goformation, you can add it:
TableClass: "STANDARD_INFREQUENT_ACCESS",
These are only one-time measures, so not accurate.
directory | framework | language |
---|---|---|
dynamodb | goformation | GO |
dynamodb-cdk-go | CDK | GO |
dynamodb-cdk-ts | CDK | Typescript |
Now I compare the execution times:
Framework | Language | command | time [sec] |
---|---|---|---|
TypeScript | init | 24.1 | |
GO | init | 0.3 | |
goformation | GO | not needed | |
TypeScript/npx | synth | 15.8 1st time, 5.5 2nd | |
TypeScript | synth | 3.1 | |
GO | synth | 3.9 | |
GO / with build | synth | 0.9 | |
GO / binary | synth | 0.03 |
You see that abstraction has its (speed) price. goformation with included build is 3..15 times faster. When you compile the programm before, you get are 100 times faster.
So usually you gain more benefits from the abstraction, but sometimes you need full control about Resources, that are not yet available as CDK constructs. Or you want to create cloudformation, but you need a mechanism to structure and cluster your files. With goformation you may create subdirectories with modules which all create on large CloudFormation template.
See the full source on github.