-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathcloudformation_resources.go
121 lines (107 loc) · 3.66 KB
/
cloudformation_resources.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package sparta
import (
"bytes"
"fmt"
"reflect"
"strings"
"text/template"
gof "github.com/awslabs/goformation/v5/cloudformation"
spartaCF "github.com/mweagle/Sparta/v3/aws/cloudformation"
cwCustomProvider "github.com/mweagle/Sparta/v3/aws/cloudformation/provider"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)
var metadataInterface = reflect.TypeOf(map[string]interface{}{})
var dependsOnInterface = reflect.TypeOf([]string{})
func newCloudFormationResource(resourceType string, logger *zerolog.Logger) (gof.Resource, error) {
resProps, _ := cwCustomProvider.NewCloudFormationCustomResource(resourceType, logger)
if nil == resProps {
logger.Fatal().
Str("Type", resourceType).
Msg("Failed to create CloudFormation CustomResource!")
return nil, fmt.Errorf("unsupported CustomResourceType: %s", resourceType)
}
return resProps, nil
}
type discoveryDataTemplate struct {
ResourceID string
ResourceType string
ResourceProperties string
}
var discoveryDataForResourceDependency = `
{
"ResourceID" : "<< .ResourceID >>",
"ResourceRef" : "{"Ref":"<< .ResourceID >>"}",
"ResourceType" : "<< .ResourceType >>",
"Properties" : {
<< .ResourceProperties >>
}
}
`
func discoveryResourceInfoForDependency(cfTemplate *gof.Template,
logicalResourceName string,
logger *zerolog.Logger) ([]byte, error) {
item, ok := cfTemplate.Resources[logicalResourceName]
if !ok {
return nil, nil
}
resourceOutputs, resourceOutputsErr := spartaCF.ResourceOutputs(logicalResourceName,
item,
logger)
if resourceOutputsErr != nil {
return nil, resourceOutputsErr
}
// Template data
templateData := &discoveryDataTemplate{
ResourceID: logicalResourceName,
ResourceType: item.AWSCloudFormationType(),
}
quotedAttrs := make([]string, len(resourceOutputs))
for eachIndex, eachOutput := range resourceOutputs {
quotedAttrs[eachIndex] = fmt.Sprintf(`"%s" :"{ "Fn::GetAtt" : [ "%s", "%s" ] }"`,
eachOutput,
logicalResourceName,
eachOutput)
}
templateData.ResourceProperties = strings.Join(quotedAttrs, ",")
// Create the data that can be stuffed into Environment
discoveryTemplate, discoveryTemplateErr := template.New("discoveryResourceData").
Delims("<<", ">>").
Parse(discoveryDataForResourceDependency)
if nil != discoveryTemplateErr {
return nil, discoveryTemplateErr
}
var templateResults bytes.Buffer
evalResultErr := discoveryTemplate.Execute(&templateResults, templateData)
return templateResults.Bytes(), evalResultErr
}
func safeAppendDependency(resource gof.Resource, dependencyName string) error {
val := reflect.ValueOf(resource).Elem()
dependsOnField := val.FieldByName("AWSCloudFormationDependsOn")
if dependsOnField.IsValid() && dependsOnField.CanConvert(dependsOnInterface) {
dependsArray := dependsOnField.Interface().([]string)
if dependsArray == nil {
dependsArray = []string{}
}
dependsArray = append(dependsArray, dependencyName)
reflectMapVal := reflect.ValueOf(dependsArray)
dependsOnField.Set(reflectMapVal)
return nil
}
return errors.Errorf("Failed to set Dependencies for resource: %v", resource)
}
func safeMetadataInsert(resource gof.Resource, key string, value interface{}) error {
val := reflect.ValueOf(resource).Elem()
metadataField := val.FieldByName("AWSCloudFormationMetadata")
if metadataField.IsValid() && metadataField.CanConvert(metadataInterface) {
metadataMap := metadataField.Interface().(map[string]interface{})
if metadataMap == nil {
metadataMap = make(map[string]interface{})
}
metadataMap[key] = value
reflectMapVal := reflect.ValueOf(metadataMap)
metadataField.Set(reflectMapVal)
return nil
}
return errors.Errorf("Failed to set Metadata for resource: %v", resource)
}