Repository navigation
Expand file tree
/
Copy pathresource_builder.go
More file actions
147 lines (124 loc) · 3.87 KB
/
Copy pathresource_builder.go
File metadata and controls
147 lines (124 loc) · 3.87 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package diff
import (
"strings"
"github.com/hashicorp/terraform/flatmap"
"github.com/hashicorp/terraform/terraform"
)
// AttrType is an enum that tells the ResourceBuilder what type of attribute
// an attribute is, affecting the overall diff output.
//
// The valid values are:
//
// * AttrTypeCreate - This attribute can only be set or updated on create.
// This means that if this attribute is changed, it will require a new
// resource to be created if it is already created.
//
// * AttrTypeUpdate - This attribute can be set at create time or updated
// in-place. Changing this attribute does not require a new resource.
//
type AttrType byte
const (
AttrTypeUnknown AttrType = iota
AttrTypeCreate
AttrTypeUpdate
)
// ResourceBuilder is a helper that knows about how a single resource
// changes and how those changes affect the diff.
type ResourceBuilder struct {
// Attrs are the mapping of attributes that can be set from the
// configuration, and the affect they have. See the documentation for
// AttrType for more info.
Attrs map[string]AttrType
// ComputedAttrs are the attributes that are computed at
// resource creation time.
ComputedAttrs []string
}
// Diff returns the ResourceDiff for a resource given its state and
// configuration.
func (b *ResourceBuilder) Diff(
s *terraform.ResourceState,
c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) {
attrs := make(map[string]*terraform.ResourceAttrDiff)
// We require a new resource if the ID is empty. Or, later, we set
// this to true if any configuration changed that triggers a new resource.
requiresNew := s.ID == ""
// Flatten the raw and processed configuration
flatRaw := flatmap.Flatten(c.Raw)
flatConfig := flatmap.Flatten(c.Config)
for ak, at := range b.Attrs {
// Keep track of all the keys we saw in the raw structure
// so that we can prune our attributes later.
seenKeys := make([]string, 0)
// Go through and find the added/changed keys in flatRaw
for k, v := range flatRaw {
// Find only the attributes that match our prefix
if !strings.HasPrefix(k, ak) {
continue
}
// Track that we saw this key
seenKeys = append(seenKeys, k)
// If this key is in the cleaned config, then use that value
// because it'll have its variables properly interpolated
if cleanV, ok := flatConfig[k]; ok {
v = cleanV
}
oldV, ok := s.Attributes[k]
// If there is an old value and they're the same, no change
if ok && oldV == v {
continue
}
// Record the change
attrs[k] = &terraform.ResourceAttrDiff{
Old: oldV,
New: v,
Type: terraform.DiffAttrInput,
}
// If this requires a new resource, record that and flag our
// boolean.
if at == AttrTypeCreate {
attrs[k].RequiresNew = true
requiresNew = true
}
}
// Go through our attribues and find the deleted keys
matchingKeys := make(map[string]struct{})
for k, _ := range s.Attributes {
// Find only the attributes that match our prefix
if !strings.HasPrefix(k, ak) {
continue
}
matchingKeys[k] = struct{}{}
}
// Delete the keys we saw to find the deleted keys
for _, k := range seenKeys {
delete(matchingKeys, k)
}
for k, _ := range matchingKeys {
attrs[k] = &terraform.ResourceAttrDiff{
Old: s.Attributes[k],
New: "",
Type: terraform.DiffAttrInput,
}
}
}
// If we require a new resource, then process all the attributes
// that will be changing due to the creation of the resource.
if requiresNew {
for _, k := range b.ComputedAttrs {
old := s.Attributes[k]
attrs[k] = &terraform.ResourceAttrDiff{
Old: old,
NewComputed: true,
Type: terraform.DiffAttrOutput,
}
}
}
// Build our resulting diff if we had attributes change
var result *terraform.ResourceDiff
if len(attrs) > 0 {
result = &terraform.ResourceDiff{
Attributes: attrs,
}
}
return result, nil
}