package build import ( "errors" "fmt" "os" "github.com/aws-cloudformation/rain/cft" "github.com/aws-cloudformation/rain/cft/parse" "github.com/aws-cloudformation/rain/cft/spec" ) // cfnBuilder contains specific code for building cloudformation templates type cfnBuilder struct { builder } // newCfnBuilder creates a new cfnBuilder func newCfnBuilder(includeOptional, buildIamPolicies bool) cfnBuilder { var b cfnBuilder b.Spec = spec.Cfn b.IncludeOptionalProperties = includeOptional b.BuildIamPolicies = buildIamPolicies return b } // Template produces a CloudFormation template for the // resources in the config map func (b cfnBuilder) Template(config map[string]string) (cft.Template, error) { defer func() { if r := recover(); r != nil { fmt.Fprintln(os.Stderr, r) if err, ok := r.(error); ok { for err != nil { fmt.Fprintln(os.Stderr, err.Error()) err = errors.Unwrap(err) } panic(err) } else { panic(r) } } }() // Generate resources resources := make(map[string]interface{}) comments := make([]*cft.Comment, 0) for name, typeName := range config { r, cs := b.newResource(typeName) resources[name] = r for _, c := range cs { c.Path = append([]interface{}{"Resources", name}, c.Path...) } comments = append(comments, cs...) } template := map[string]interface{}{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Template generated by rain", "Resources": resources, } if b.IncludeOptionalProperties { outputs := make(map[string]interface{}) for name, typeName := range config { r := b.Spec.ResourceTypes[typeName] for attName := range r.Attributes { outputs[name+attName] = map[string]interface{}{ "Value": map[string]interface{}{ "Fn::GetAtt": name + "." + attName, }, } } } template["Outputs"] = outputs } // Build the template t, err := parse.Map(template) if err != nil { return t, err } if b.IncludeOptionalProperties { t.AddComments(comments) } return t, nil } // Template returns a cft.Template populate with resources derived from // the provided config which should be a map of resource names to resources types // includeOptionalProperties determines whether or not the generated template // will include optional properties. If it does, comments will be added to identify // which properties are optional func Template(config map[string]string, includeOptionalProperties bool) (cft.Template, error) { b := newCfnBuilder(includeOptionalProperties, true) return b.Template(config) }