diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go new file mode 100644 index 0000000..16bbae2 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go | |||
@@ -0,0 +1,208 @@ | |||
1 | package schema | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "strings" | ||
6 | |||
7 | "github.com/hashicorp/terraform/terraform" | ||
8 | "github.com/mitchellh/mapstructure" | ||
9 | ) | ||
10 | |||
11 | // DiffFieldReader reads fields out of a diff structures. | ||
12 | // | ||
13 | // It also requires access to a Reader that reads fields from the structure | ||
14 | // that the diff was derived from. This is usually the state. This is required | ||
15 | // because a diff on its own doesn't have complete data about full objects | ||
16 | // such as maps. | ||
17 | // | ||
18 | // The Source MUST be the data that the diff was derived from. If it isn't, | ||
19 | // the behavior of this struct is undefined. | ||
20 | // | ||
21 | // Reading fields from a DiffFieldReader is identical to reading from | ||
22 | // Source except the diff will be applied to the end result. | ||
23 | // | ||
24 | // The "Exists" field on the result will be set to true if the complete | ||
25 | // field exists whether its from the source, diff, or a combination of both. | ||
26 | // It cannot be determined whether a retrieved value is composed of | ||
27 | // diff elements. | ||
28 | type DiffFieldReader struct { | ||
29 | Diff *terraform.InstanceDiff | ||
30 | Source FieldReader | ||
31 | Schema map[string]*Schema | ||
32 | } | ||
33 | |||
34 | func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) { | ||
35 | schemaList := addrToSchema(address, r.Schema) | ||
36 | if len(schemaList) == 0 { | ||
37 | return FieldReadResult{}, nil | ||
38 | } | ||
39 | |||
40 | schema := schemaList[len(schemaList)-1] | ||
41 | switch schema.Type { | ||
42 | case TypeBool, TypeInt, TypeFloat, TypeString: | ||
43 | return r.readPrimitive(address, schema) | ||
44 | case TypeList: | ||
45 | return readListField(r, address, schema) | ||
46 | case TypeMap: | ||
47 | return r.readMap(address, schema) | ||
48 | case TypeSet: | ||
49 | return r.readSet(address, schema) | ||
50 | case typeObject: | ||
51 | return readObjectField(r, address, schema.Elem.(map[string]*Schema)) | ||
52 | default: | ||
53 | panic(fmt.Sprintf("Unknown type: %#v", schema.Type)) | ||
54 | } | ||
55 | } | ||
56 | |||
57 | func (r *DiffFieldReader) readMap( | ||
58 | address []string, schema *Schema) (FieldReadResult, error) { | ||
59 | result := make(map[string]interface{}) | ||
60 | resultSet := false | ||
61 | |||
62 | // First read the map from the underlying source | ||
63 | source, err := r.Source.ReadField(address) | ||
64 | if err != nil { | ||
65 | return FieldReadResult{}, err | ||
66 | } | ||
67 | if source.Exists { | ||
68 | result = source.Value.(map[string]interface{}) | ||
69 | resultSet = true | ||
70 | } | ||
71 | |||
72 | // Next, read all the elements we have in our diff, and apply | ||
73 | // the diff to our result. | ||
74 | prefix := strings.Join(address, ".") + "." | ||
75 | for k, v := range r.Diff.Attributes { | ||
76 | if !strings.HasPrefix(k, prefix) { | ||
77 | continue | ||
78 | } | ||
79 | if strings.HasPrefix(k, prefix+"%") { | ||
80 | // Ignore the count field | ||
81 | continue | ||
82 | } | ||
83 | |||
84 | resultSet = true | ||
85 | |||
86 | k = k[len(prefix):] | ||
87 | if v.NewRemoved { | ||
88 | delete(result, k) | ||
89 | continue | ||
90 | } | ||
91 | |||
92 | result[k] = v.New | ||
93 | } | ||
94 | |||
95 | err = mapValuesToPrimitive(result, schema) | ||
96 | if err != nil { | ||
97 | return FieldReadResult{}, nil | ||
98 | } | ||
99 | |||
100 | var resultVal interface{} | ||
101 | if resultSet { | ||
102 | resultVal = result | ||
103 | } | ||
104 | |||
105 | return FieldReadResult{ | ||
106 | Value: resultVal, | ||
107 | Exists: resultSet, | ||
108 | }, nil | ||
109 | } | ||
110 | |||
111 | func (r *DiffFieldReader) readPrimitive( | ||
112 | address []string, schema *Schema) (FieldReadResult, error) { | ||
113 | result, err := r.Source.ReadField(address) | ||
114 | if err != nil { | ||
115 | return FieldReadResult{}, err | ||
116 | } | ||
117 | |||
118 | attrD, ok := r.Diff.Attributes[strings.Join(address, ".")] | ||
119 | if !ok { | ||
120 | return result, nil | ||
121 | } | ||
122 | |||
123 | var resultVal string | ||
124 | if !attrD.NewComputed { | ||
125 | resultVal = attrD.New | ||
126 | if attrD.NewExtra != nil { | ||
127 | result.ValueProcessed = resultVal | ||
128 | if err := mapstructure.WeakDecode(attrD.NewExtra, &resultVal); err != nil { | ||
129 | return FieldReadResult{}, err | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | result.Computed = attrD.NewComputed | ||
135 | result.Exists = true | ||
136 | result.Value, err = stringToPrimitive(resultVal, false, schema) | ||
137 | if err != nil { | ||
138 | return FieldReadResult{}, err | ||
139 | } | ||
140 | |||
141 | return result, nil | ||
142 | } | ||
143 | |||
144 | func (r *DiffFieldReader) readSet( | ||
145 | address []string, schema *Schema) (FieldReadResult, error) { | ||
146 | prefix := strings.Join(address, ".") + "." | ||
147 | |||
148 | // Create the set that will be our result | ||
149 | set := schema.ZeroValue().(*Set) | ||
150 | |||
151 | // Go through the map and find all the set items | ||
152 | for k, d := range r.Diff.Attributes { | ||
153 | if d.NewRemoved { | ||
154 | // If the field is removed, we always ignore it | ||
155 | continue | ||
156 | } | ||
157 | if !strings.HasPrefix(k, prefix) { | ||
158 | continue | ||
159 | } | ||
160 | if strings.HasSuffix(k, "#") { | ||
161 | // Ignore any count field | ||
162 | continue | ||
163 | } | ||
164 | |||
165 | // Split the key, since it might be a sub-object like "idx.field" | ||
166 | parts := strings.Split(k[len(prefix):], ".") | ||
167 | idx := parts[0] | ||
168 | |||
169 | raw, err := r.ReadField(append(address, idx)) | ||
170 | if err != nil { | ||
171 | return FieldReadResult{}, err | ||
172 | } | ||
173 | if !raw.Exists { | ||
174 | // This shouldn't happen because we just verified it does exist | ||
175 | panic("missing field in set: " + k + "." + idx) | ||
176 | } | ||
177 | |||
178 | set.Add(raw.Value) | ||
179 | } | ||
180 | |||
181 | // Determine if the set "exists". It exists if there are items or if | ||
182 | // the diff explicitly wanted it empty. | ||
183 | exists := set.Len() > 0 | ||
184 | if !exists { | ||
185 | // We could check if the diff value is "0" here but I think the | ||
186 | // existence of "#" on its own is enough to show it existed. This | ||
187 | // protects us in the future from the zero value changing from | ||
188 | // "0" to "" breaking us (if that were to happen). | ||
189 | if _, ok := r.Diff.Attributes[prefix+"#"]; ok { | ||
190 | exists = true | ||
191 | } | ||
192 | } | ||
193 | |||
194 | if !exists { | ||
195 | result, err := r.Source.ReadField(address) | ||
196 | if err != nil { | ||
197 | return FieldReadResult{}, err | ||
198 | } | ||
199 | if result.Exists { | ||
200 | return result, nil | ||
201 | } | ||
202 | } | ||
203 | |||
204 | return FieldReadResult{ | ||
205 | Value: set, | ||
206 | Exists: exists, | ||
207 | }, nil | ||
208 | } | ||