diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/state_add.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/state_add.go | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/state_add.go b/vendor/github.com/hashicorp/terraform/terraform/state_add.go new file mode 100644 index 0000000..1163730 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/state_add.go | |||
@@ -0,0 +1,374 @@ | |||
1 | package terraform | ||
2 | |||
3 | import "fmt" | ||
4 | |||
5 | // Add adds the item in the state at the given address. | ||
6 | // | ||
7 | // The item can be a ModuleState, ResourceState, or InstanceState. Depending | ||
8 | // on the item type, the address may or may not be valid. For example, a | ||
9 | // module cannot be moved to a resource address, however a resource can be | ||
10 | // moved to a module address (it retains the same name, under that resource). | ||
11 | // | ||
12 | // The item can also be a []*ModuleState, which is the case for nested | ||
13 | // modules. In this case, Add will expect the zero-index to be the top-most | ||
14 | // module to add and will only nest children from there. For semantics, this | ||
15 | // is equivalent to module => module. | ||
16 | // | ||
17 | // The full semantics of Add: | ||
18 | // | ||
19 | // ┌───────────────────┬───────────────────┬───────────────────┐ | ||
20 | // │ Module Address │ Resource Address │ Instance Address │ | ||
21 | // ┌─────────────────┼───────────────────┼───────────────────┼───────────────────┤ | ||
22 | // │ ModuleState │ ✓ │ x │ x │ | ||
23 | // ├─────────────────┼───────────────────┼───────────────────┼───────────────────┤ | ||
24 | // │ ResourceState │ ✓ │ ✓ │ maybe* │ | ||
25 | // ├─────────────────┼───────────────────┼───────────────────┼───────────────────┤ | ||
26 | // │ Instance State │ ✓ │ ✓ │ ✓ │ | ||
27 | // └─────────────────┴───────────────────┴───────────────────┴───────────────────┘ | ||
28 | // | ||
29 | // *maybe - Resources can be added at an instance address only if the resource | ||
30 | // represents a single instance (primary). Example: | ||
31 | // "aws_instance.foo" can be moved to "aws_instance.bar.tainted" | ||
32 | // | ||
33 | func (s *State) Add(fromAddrRaw string, toAddrRaw string, raw interface{}) error { | ||
34 | // Parse the address | ||
35 | |||
36 | toAddr, err := ParseResourceAddress(toAddrRaw) | ||
37 | if err != nil { | ||
38 | return err | ||
39 | } | ||
40 | |||
41 | // Parse the from address | ||
42 | fromAddr, err := ParseResourceAddress(fromAddrRaw) | ||
43 | if err != nil { | ||
44 | return err | ||
45 | } | ||
46 | |||
47 | // Determine the types | ||
48 | from := detectValueAddLoc(raw) | ||
49 | to := detectAddrAddLoc(toAddr) | ||
50 | |||
51 | // Find the function to do this | ||
52 | fromMap, ok := stateAddFuncs[from] | ||
53 | if !ok { | ||
54 | return fmt.Errorf("invalid source to add to state: %T", raw) | ||
55 | } | ||
56 | f, ok := fromMap[to] | ||
57 | if !ok { | ||
58 | return fmt.Errorf("invalid destination: %s (%d)", toAddr, to) | ||
59 | } | ||
60 | |||
61 | // Call the migrator | ||
62 | if err := f(s, fromAddr, toAddr, raw); err != nil { | ||
63 | return err | ||
64 | } | ||
65 | |||
66 | // Prune the state | ||
67 | s.prune() | ||
68 | return nil | ||
69 | } | ||
70 | |||
71 | func stateAddFunc_Module_Module(s *State, fromAddr, addr *ResourceAddress, raw interface{}) error { | ||
72 | // raw can be either *ModuleState or []*ModuleState. The former means | ||
73 | // we're moving just one module. The latter means we're moving a module | ||
74 | // and children. | ||
75 | root := raw | ||
76 | var rest []*ModuleState | ||
77 | if list, ok := raw.([]*ModuleState); ok { | ||
78 | // We need at least one item | ||
79 | if len(list) == 0 { | ||
80 | return fmt.Errorf("module move with no value to: %s", addr) | ||
81 | } | ||
82 | |||
83 | // The first item is always the root | ||
84 | root = list[0] | ||
85 | if len(list) > 1 { | ||
86 | rest = list[1:] | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // Get the actual module state | ||
91 | src := root.(*ModuleState).deepcopy() | ||
92 | |||
93 | // If the target module exists, it is an error | ||
94 | path := append([]string{"root"}, addr.Path...) | ||
95 | if s.ModuleByPath(path) != nil { | ||
96 | return fmt.Errorf("module target is not empty: %s", addr) | ||
97 | } | ||
98 | |||
99 | // Create it and copy our outputs and dependencies | ||
100 | mod := s.AddModule(path) | ||
101 | mod.Outputs = src.Outputs | ||
102 | mod.Dependencies = src.Dependencies | ||
103 | |||
104 | // Go through the resources perform an add for each of those | ||
105 | for k, v := range src.Resources { | ||
106 | resourceKey, err := ParseResourceStateKey(k) | ||
107 | if err != nil { | ||
108 | return err | ||
109 | } | ||
110 | |||
111 | // Update the resource address for this | ||
112 | addrCopy := *addr | ||
113 | addrCopy.Type = resourceKey.Type | ||
114 | addrCopy.Name = resourceKey.Name | ||
115 | addrCopy.Index = resourceKey.Index | ||
116 | addrCopy.Mode = resourceKey.Mode | ||
117 | |||
118 | // Perform an add | ||
119 | if err := s.Add(fromAddr.String(), addrCopy.String(), v); err != nil { | ||
120 | return err | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // Add all the children if we have them | ||
125 | for _, item := range rest { | ||
126 | // If item isn't a descendent of our root, then ignore it | ||
127 | if !src.IsDescendent(item) { | ||
128 | continue | ||
129 | } | ||
130 | |||
131 | // It is! Strip the leading prefix and attach that to our address | ||
132 | extra := item.Path[len(src.Path):] | ||
133 | addrCopy := addr.Copy() | ||
134 | addrCopy.Path = append(addrCopy.Path, extra...) | ||
135 | |||
136 | // Add it | ||
137 | s.Add(fromAddr.String(), addrCopy.String(), item) | ||
138 | } | ||
139 | |||
140 | return nil | ||
141 | } | ||
142 | |||
143 | func stateAddFunc_Resource_Module( | ||
144 | s *State, from, to *ResourceAddress, raw interface{}) error { | ||
145 | // Build the more specific to addr | ||
146 | addr := *to | ||
147 | addr.Type = from.Type | ||
148 | addr.Name = from.Name | ||
149 | |||
150 | return s.Add(from.String(), addr.String(), raw) | ||
151 | } | ||
152 | |||
153 | func stateAddFunc_Resource_Resource(s *State, fromAddr, addr *ResourceAddress, raw interface{}) error { | ||
154 | // raw can be either *ResourceState or []*ResourceState. The former means | ||
155 | // we're moving just one resource. The latter means we're moving a count | ||
156 | // of resources. | ||
157 | if list, ok := raw.([]*ResourceState); ok { | ||
158 | // We need at least one item | ||
159 | if len(list) == 0 { | ||
160 | return fmt.Errorf("resource move with no value to: %s", addr) | ||
161 | } | ||
162 | |||
163 | // If there is an index, this is an error since we can't assign | ||
164 | // a set of resources to a single index | ||
165 | if addr.Index >= 0 && len(list) > 1 { | ||
166 | return fmt.Errorf( | ||
167 | "multiple resources can't be moved to a single index: "+ | ||
168 | "%s => %s", fromAddr, addr) | ||
169 | } | ||
170 | |||
171 | // Add each with a specific index | ||
172 | for i, rs := range list { | ||
173 | addrCopy := addr.Copy() | ||
174 | addrCopy.Index = i | ||
175 | |||
176 | if err := s.Add(fromAddr.String(), addrCopy.String(), rs); err != nil { | ||
177 | return err | ||
178 | } | ||
179 | } | ||
180 | |||
181 | return nil | ||
182 | } | ||
183 | |||
184 | src := raw.(*ResourceState).deepcopy() | ||
185 | |||
186 | // Initialize the resource | ||
187 | resourceRaw, exists := stateAddInitAddr(s, addr) | ||
188 | if exists { | ||
189 | return fmt.Errorf("resource exists and not empty: %s", addr) | ||
190 | } | ||
191 | resource := resourceRaw.(*ResourceState) | ||
192 | resource.Type = src.Type | ||
193 | resource.Dependencies = src.Dependencies | ||
194 | resource.Provider = src.Provider | ||
195 | |||
196 | // Move the primary | ||
197 | if src.Primary != nil { | ||
198 | addrCopy := *addr | ||
199 | addrCopy.InstanceType = TypePrimary | ||
200 | addrCopy.InstanceTypeSet = true | ||
201 | if err := s.Add(fromAddr.String(), addrCopy.String(), src.Primary); err != nil { | ||
202 | return err | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // Move all deposed | ||
207 | if len(src.Deposed) > 0 { | ||
208 | resource.Deposed = src.Deposed | ||
209 | } | ||
210 | |||
211 | return nil | ||
212 | } | ||
213 | |||
214 | func stateAddFunc_Instance_Instance(s *State, fromAddr, addr *ResourceAddress, raw interface{}) error { | ||
215 | src := raw.(*InstanceState).DeepCopy() | ||
216 | |||
217 | // Create the instance | ||
218 | instanceRaw, _ := stateAddInitAddr(s, addr) | ||
219 | instance := instanceRaw.(*InstanceState) | ||
220 | |||
221 | // Set it | ||
222 | instance.Set(src) | ||
223 | |||
224 | return nil | ||
225 | } | ||
226 | |||
227 | func stateAddFunc_Instance_Module( | ||
228 | s *State, from, to *ResourceAddress, raw interface{}) error { | ||
229 | addr := *to | ||
230 | addr.Type = from.Type | ||
231 | addr.Name = from.Name | ||
232 | |||
233 | return s.Add(from.String(), addr.String(), raw) | ||
234 | } | ||
235 | |||
236 | func stateAddFunc_Instance_Resource( | ||
237 | s *State, from, to *ResourceAddress, raw interface{}) error { | ||
238 | addr := *to | ||
239 | addr.InstanceType = TypePrimary | ||
240 | addr.InstanceTypeSet = true | ||
241 | |||
242 | return s.Add(from.String(), addr.String(), raw) | ||
243 | } | ||
244 | |||
245 | // stateAddFunc is the type of function for adding an item to a state | ||
246 | type stateAddFunc func(s *State, from, to *ResourceAddress, item interface{}) error | ||
247 | |||
248 | // stateAddFuncs has the full matrix mapping of the state adders. | ||
249 | var stateAddFuncs map[stateAddLoc]map[stateAddLoc]stateAddFunc | ||
250 | |||
251 | func init() { | ||
252 | stateAddFuncs = map[stateAddLoc]map[stateAddLoc]stateAddFunc{ | ||
253 | stateAddModule: { | ||
254 | stateAddModule: stateAddFunc_Module_Module, | ||
255 | }, | ||
256 | stateAddResource: { | ||
257 | stateAddModule: stateAddFunc_Resource_Module, | ||
258 | stateAddResource: stateAddFunc_Resource_Resource, | ||
259 | }, | ||
260 | stateAddInstance: { | ||
261 | stateAddInstance: stateAddFunc_Instance_Instance, | ||
262 | stateAddModule: stateAddFunc_Instance_Module, | ||
263 | stateAddResource: stateAddFunc_Instance_Resource, | ||
264 | }, | ||
265 | } | ||
266 | } | ||
267 | |||
268 | // stateAddLoc is an enum to represent the location where state is being | ||
269 | // moved from/to. We use this for quick lookups in a function map. | ||
270 | type stateAddLoc uint | ||
271 | |||
272 | const ( | ||
273 | stateAddInvalid stateAddLoc = iota | ||
274 | stateAddModule | ||
275 | stateAddResource | ||
276 | stateAddInstance | ||
277 | ) | ||
278 | |||
279 | // detectAddrAddLoc detects the state type for the given address. This | ||
280 | // function is specifically not unit tested since we consider the State.Add | ||
281 | // functionality to be comprehensive enough to cover this. | ||
282 | func detectAddrAddLoc(addr *ResourceAddress) stateAddLoc { | ||
283 | if addr.Name == "" { | ||
284 | return stateAddModule | ||
285 | } | ||
286 | |||
287 | if !addr.InstanceTypeSet { | ||
288 | return stateAddResource | ||
289 | } | ||
290 | |||
291 | return stateAddInstance | ||
292 | } | ||
293 | |||
294 | // detectValueAddLoc determines the stateAddLoc value from the raw value | ||
295 | // that is some State structure. | ||
296 | func detectValueAddLoc(raw interface{}) stateAddLoc { | ||
297 | switch raw.(type) { | ||
298 | case *ModuleState: | ||
299 | return stateAddModule | ||
300 | case []*ModuleState: | ||
301 | return stateAddModule | ||
302 | case *ResourceState: | ||
303 | return stateAddResource | ||
304 | case []*ResourceState: | ||
305 | return stateAddResource | ||
306 | case *InstanceState: | ||
307 | return stateAddInstance | ||
308 | default: | ||
309 | return stateAddInvalid | ||
310 | } | ||
311 | } | ||
312 | |||
313 | // stateAddInitAddr takes a ResourceAddress and creates the non-existing | ||
314 | // resources up to that point, returning the empty (or existing) interface | ||
315 | // at that address. | ||
316 | func stateAddInitAddr(s *State, addr *ResourceAddress) (interface{}, bool) { | ||
317 | addType := detectAddrAddLoc(addr) | ||
318 | |||
319 | // Get the module | ||
320 | path := append([]string{"root"}, addr.Path...) | ||
321 | exists := true | ||
322 | mod := s.ModuleByPath(path) | ||
323 | if mod == nil { | ||
324 | mod = s.AddModule(path) | ||
325 | exists = false | ||
326 | } | ||
327 | if addType == stateAddModule { | ||
328 | return mod, exists | ||
329 | } | ||
330 | |||
331 | // Add the resource | ||
332 | resourceKey := (&ResourceStateKey{ | ||
333 | Name: addr.Name, | ||
334 | Type: addr.Type, | ||
335 | Index: addr.Index, | ||
336 | Mode: addr.Mode, | ||
337 | }).String() | ||
338 | exists = true | ||
339 | resource, ok := mod.Resources[resourceKey] | ||
340 | if !ok { | ||
341 | resource = &ResourceState{Type: addr.Type} | ||
342 | resource.init() | ||
343 | mod.Resources[resourceKey] = resource | ||
344 | exists = false | ||
345 | } | ||
346 | if addType == stateAddResource { | ||
347 | return resource, exists | ||
348 | } | ||
349 | |||
350 | // Get the instance | ||
351 | exists = true | ||
352 | instance := &InstanceState{} | ||
353 | switch addr.InstanceType { | ||
354 | case TypePrimary, TypeTainted: | ||
355 | if v := resource.Primary; v != nil { | ||
356 | instance = resource.Primary | ||
357 | } else { | ||
358 | exists = false | ||
359 | } | ||
360 | case TypeDeposed: | ||
361 | idx := addr.Index | ||
362 | if addr.Index < 0 { | ||
363 | idx = 0 | ||
364 | } | ||
365 | if len(resource.Deposed) > idx { | ||
366 | instance = resource.Deposed[idx] | ||
367 | } else { | ||
368 | resource.Deposed = append(resource.Deposed, instance) | ||
369 | exists = false | ||
370 | } | ||
371 | } | ||
372 | |||
373 | return instance, exists | ||
374 | } | ||