]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "bufio" | |
5 | "bytes" | |
6 | "encoding/json" | |
7 | "errors" | |
8 | "fmt" | |
9 | "io" | |
10 | "io/ioutil" | |
11 | "log" | |
12 | "reflect" | |
13 | "sort" | |
14 | "strconv" | |
15 | "strings" | |
16 | "sync" | |
17 | ||
18 | "github.com/hashicorp/go-multierror" | |
19 | "github.com/hashicorp/go-version" | |
20 | "github.com/hashicorp/terraform/config" | |
21 | "github.com/mitchellh/copystructure" | |
22 | "github.com/satori/go.uuid" | |
23 | ) | |
24 | ||
25 | const ( | |
26 | // StateVersion is the current version for our state file | |
27 | StateVersion = 3 | |
28 | ) | |
29 | ||
30 | // rootModulePath is the path of the root module | |
31 | var rootModulePath = []string{"root"} | |
32 | ||
33 | // normalizeModulePath takes a raw module path and returns a path that | |
34 | // has the rootModulePath prepended to it. If I could go back in time I | |
35 | // would've never had a rootModulePath (empty path would be root). We can | |
36 | // still fix this but thats a big refactor that my branch doesn't make sense | |
37 | // for. Instead, this function normalizes paths. | |
38 | func normalizeModulePath(p []string) []string { | |
39 | k := len(rootModulePath) | |
40 | ||
41 | // If we already have a root module prefix, we're done | |
42 | if len(p) >= len(rootModulePath) { | |
43 | if reflect.DeepEqual(p[:k], rootModulePath) { | |
44 | return p | |
45 | } | |
46 | } | |
47 | ||
48 | // None? Prefix it | |
49 | result := make([]string, len(rootModulePath)+len(p)) | |
50 | copy(result, rootModulePath) | |
51 | copy(result[k:], p) | |
52 | return result | |
53 | } | |
54 | ||
55 | // State keeps track of a snapshot state-of-the-world that Terraform | |
56 | // can use to keep track of what real world resources it is actually | |
57 | // managing. | |
58 | type State struct { | |
59 | // Version is the state file protocol version. | |
60 | Version int `json:"version"` | |
61 | ||
62 | // TFVersion is the version of Terraform that wrote this state. | |
63 | TFVersion string `json:"terraform_version,omitempty"` | |
64 | ||
65 | // Serial is incremented on any operation that modifies | |
66 | // the State file. It is used to detect potentially conflicting | |
67 | // updates. | |
68 | Serial int64 `json:"serial"` | |
69 | ||
70 | // Lineage is set when a new, blank state is created and then | |
71 | // never updated. This allows us to determine whether the serials | |
72 | // of two states can be meaningfully compared. | |
73 | // Apart from the guarantee that collisions between two lineages | |
74 | // are very unlikely, this value is opaque and external callers | |
75 | // should only compare lineage strings byte-for-byte for equality. | |
76 | Lineage string `json:"lineage"` | |
77 | ||
78 | // Remote is used to track the metadata required to | |
79 | // pull and push state files from a remote storage endpoint. | |
80 | Remote *RemoteState `json:"remote,omitempty"` | |
81 | ||
82 | // Backend tracks the configuration for the backend in use with | |
83 | // this state. This is used to track any changes in the backend | |
84 | // configuration. | |
85 | Backend *BackendState `json:"backend,omitempty"` | |
86 | ||
87 | // Modules contains all the modules in a breadth-first order | |
88 | Modules []*ModuleState `json:"modules"` | |
89 | ||
90 | mu sync.Mutex | |
91 | } | |
92 | ||
93 | func (s *State) Lock() { s.mu.Lock() } | |
94 | func (s *State) Unlock() { s.mu.Unlock() } | |
95 | ||
96 | // NewState is used to initialize a blank state | |
97 | func NewState() *State { | |
98 | s := &State{} | |
99 | s.init() | |
100 | return s | |
101 | } | |
102 | ||
103 | // Children returns the ModuleStates that are direct children of | |
104 | // the given path. If the path is "root", for example, then children | |
105 | // returned might be "root.child", but not "root.child.grandchild". | |
106 | func (s *State) Children(path []string) []*ModuleState { | |
107 | s.Lock() | |
108 | defer s.Unlock() | |
109 | // TODO: test | |
110 | ||
111 | return s.children(path) | |
112 | } | |
113 | ||
114 | func (s *State) children(path []string) []*ModuleState { | |
115 | result := make([]*ModuleState, 0) | |
116 | for _, m := range s.Modules { | |
117 | if m == nil { | |
118 | continue | |
119 | } | |
120 | ||
121 | if len(m.Path) != len(path)+1 { | |
122 | continue | |
123 | } | |
124 | if !reflect.DeepEqual(path, m.Path[:len(path)]) { | |
125 | continue | |
126 | } | |
127 | ||
128 | result = append(result, m) | |
129 | } | |
130 | ||
131 | return result | |
132 | } | |
133 | ||
134 | // AddModule adds the module with the given path to the state. | |
135 | // | |
136 | // This should be the preferred method to add module states since it | |
137 | // allows us to optimize lookups later as well as control sorting. | |
138 | func (s *State) AddModule(path []string) *ModuleState { | |
139 | s.Lock() | |
140 | defer s.Unlock() | |
141 | ||
142 | return s.addModule(path) | |
143 | } | |
144 | ||
145 | func (s *State) addModule(path []string) *ModuleState { | |
146 | // check if the module exists first | |
147 | m := s.moduleByPath(path) | |
148 | if m != nil { | |
149 | return m | |
150 | } | |
151 | ||
152 | m = &ModuleState{Path: path} | |
153 | m.init() | |
154 | s.Modules = append(s.Modules, m) | |
155 | s.sort() | |
156 | return m | |
157 | } | |
158 | ||
159 | // ModuleByPath is used to lookup the module state for the given path. | |
160 | // This should be the preferred lookup mechanism as it allows for future | |
161 | // lookup optimizations. | |
162 | func (s *State) ModuleByPath(path []string) *ModuleState { | |
163 | if s == nil { | |
164 | return nil | |
165 | } | |
166 | s.Lock() | |
167 | defer s.Unlock() | |
168 | ||
169 | return s.moduleByPath(path) | |
170 | } | |
171 | ||
172 | func (s *State) moduleByPath(path []string) *ModuleState { | |
173 | for _, mod := range s.Modules { | |
174 | if mod == nil { | |
175 | continue | |
176 | } | |
177 | if mod.Path == nil { | |
178 | panic("missing module path") | |
179 | } | |
180 | if reflect.DeepEqual(mod.Path, path) { | |
181 | return mod | |
182 | } | |
183 | } | |
184 | return nil | |
185 | } | |
186 | ||
187 | // ModuleOrphans returns all the module orphans in this state by | |
188 | // returning their full paths. These paths can be used with ModuleByPath | |
189 | // to return the actual state. | |
190 | func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { | |
191 | s.Lock() | |
192 | defer s.Unlock() | |
193 | ||
194 | return s.moduleOrphans(path, c) | |
195 | ||
196 | } | |
197 | ||
198 | func (s *State) moduleOrphans(path []string, c *config.Config) [][]string { | |
199 | // direct keeps track of what direct children we have both in our config | |
200 | // and in our state. childrenKeys keeps track of what isn't an orphan. | |
201 | direct := make(map[string]struct{}) | |
202 | childrenKeys := make(map[string]struct{}) | |
203 | if c != nil { | |
204 | for _, m := range c.Modules { | |
205 | childrenKeys[m.Name] = struct{}{} | |
206 | direct[m.Name] = struct{}{} | |
207 | } | |
208 | } | |
209 | ||
210 | // Go over the direct children and find any that aren't in our keys. | |
211 | var orphans [][]string | |
212 | for _, m := range s.children(path) { | |
213 | key := m.Path[len(m.Path)-1] | |
214 | ||
215 | // Record that we found this key as a direct child. We use this | |
216 | // later to find orphan nested modules. | |
217 | direct[key] = struct{}{} | |
218 | ||
219 | // If we have a direct child still in our config, it is not an orphan | |
220 | if _, ok := childrenKeys[key]; ok { | |
221 | continue | |
222 | } | |
223 | ||
224 | orphans = append(orphans, m.Path) | |
225 | } | |
226 | ||
227 | // Find the orphans that are nested... | |
228 | for _, m := range s.Modules { | |
229 | if m == nil { | |
230 | continue | |
231 | } | |
232 | ||
233 | // We only want modules that are at least grandchildren | |
234 | if len(m.Path) < len(path)+2 { | |
235 | continue | |
236 | } | |
237 | ||
238 | // If it isn't part of our tree, continue | |
239 | if !reflect.DeepEqual(path, m.Path[:len(path)]) { | |
240 | continue | |
241 | } | |
242 | ||
243 | // If we have the direct child, then just skip it. | |
244 | key := m.Path[len(path)] | |
245 | if _, ok := direct[key]; ok { | |
246 | continue | |
247 | } | |
248 | ||
249 | orphanPath := m.Path[:len(path)+1] | |
250 | ||
251 | // Don't double-add if we've already added this orphan (which can happen if | |
252 | // there are multiple nested sub-modules that get orphaned together). | |
253 | alreadyAdded := false | |
254 | for _, o := range orphans { | |
255 | if reflect.DeepEqual(o, orphanPath) { | |
256 | alreadyAdded = true | |
257 | break | |
258 | } | |
259 | } | |
260 | if alreadyAdded { | |
261 | continue | |
262 | } | |
263 | ||
264 | // Add this orphan | |
265 | orphans = append(orphans, orphanPath) | |
266 | } | |
267 | ||
268 | return orphans | |
269 | } | |
270 | ||
271 | // Empty returns true if the state is empty. | |
272 | func (s *State) Empty() bool { | |
273 | if s == nil { | |
274 | return true | |
275 | } | |
276 | s.Lock() | |
277 | defer s.Unlock() | |
278 | ||
279 | return len(s.Modules) == 0 | |
280 | } | |
281 | ||
282 | // HasResources returns true if the state contains any resources. | |
283 | // | |
284 | // This is similar to !s.Empty, but returns true also in the case where the | |
285 | // state has modules but all of them are devoid of resources. | |
286 | func (s *State) HasResources() bool { | |
287 | if s.Empty() { | |
288 | return false | |
289 | } | |
290 | ||
291 | for _, mod := range s.Modules { | |
292 | if len(mod.Resources) > 0 { | |
293 | return true | |
294 | } | |
295 | } | |
296 | ||
297 | return false | |
298 | } | |
299 | ||
300 | // IsRemote returns true if State represents a state that exists and is | |
301 | // remote. | |
302 | func (s *State) IsRemote() bool { | |
303 | if s == nil { | |
304 | return false | |
305 | } | |
306 | s.Lock() | |
307 | defer s.Unlock() | |
308 | ||
309 | if s.Remote == nil { | |
310 | return false | |
311 | } | |
312 | if s.Remote.Type == "" { | |
313 | return false | |
314 | } | |
315 | ||
316 | return true | |
317 | } | |
318 | ||
319 | // Validate validates the integrity of this state file. | |
320 | // | |
321 | // Certain properties of the statefile are expected by Terraform in order | |
322 | // to behave properly. The core of Terraform will assume that once it | |
323 | // receives a State structure that it has been validated. This validation | |
324 | // check should be called to ensure that. | |
325 | // | |
326 | // If this returns an error, then the user should be notified. The error | |
327 | // response will include detailed information on the nature of the error. | |
328 | func (s *State) Validate() error { | |
329 | s.Lock() | |
330 | defer s.Unlock() | |
331 | ||
332 | var result error | |
333 | ||
334 | // !!!! FOR DEVELOPERS !!!! | |
335 | // | |
336 | // Any errors returned from this Validate function will BLOCK TERRAFORM | |
337 | // from loading a state file. Therefore, this should only contain checks | |
338 | // that are only resolvable through manual intervention. | |
339 | // | |
340 | // !!!! FOR DEVELOPERS !!!! | |
341 | ||
342 | // Make sure there are no duplicate module states. We open a new | |
343 | // block here so we can use basic variable names and future validations | |
344 | // can do the same. | |
345 | { | |
346 | found := make(map[string]struct{}) | |
347 | for _, ms := range s.Modules { | |
348 | if ms == nil { | |
349 | continue | |
350 | } | |
351 | ||
352 | key := strings.Join(ms.Path, ".") | |
353 | if _, ok := found[key]; ok { | |
354 | result = multierror.Append(result, fmt.Errorf( | |
355 | strings.TrimSpace(stateValidateErrMultiModule), key)) | |
356 | continue | |
357 | } | |
358 | ||
359 | found[key] = struct{}{} | |
360 | } | |
361 | } | |
362 | ||
363 | return result | |
364 | } | |
365 | ||
366 | // Remove removes the item in the state at the given address, returning | |
367 | // any errors that may have occurred. | |
368 | // | |
369 | // If the address references a module state or resource, it will delete | |
370 | // all children as well. To check what will be deleted, use a StateFilter | |
371 | // first. | |
372 | func (s *State) Remove(addr ...string) error { | |
373 | s.Lock() | |
374 | defer s.Unlock() | |
375 | ||
376 | // Filter out what we need to delete | |
377 | filter := &StateFilter{State: s} | |
378 | results, err := filter.Filter(addr...) | |
379 | if err != nil { | |
380 | return err | |
381 | } | |
382 | ||
383 | // If we have no results, just exit early, we're not going to do anything. | |
384 | // While what happens below is fairly fast, this is an important early | |
385 | // exit since the prune below might modify the state more and we don't | |
386 | // want to modify the state if we don't have to. | |
387 | if len(results) == 0 { | |
388 | return nil | |
389 | } | |
390 | ||
391 | // Go through each result and grab what we need | |
392 | removed := make(map[interface{}]struct{}) | |
393 | for _, r := range results { | |
394 | // Convert the path to our own type | |
395 | path := append([]string{"root"}, r.Path...) | |
396 | ||
397 | // If we removed this already, then ignore | |
398 | if _, ok := removed[r.Value]; ok { | |
399 | continue | |
400 | } | |
401 | ||
402 | // If we removed the parent already, then ignore | |
403 | if r.Parent != nil { | |
404 | if _, ok := removed[r.Parent.Value]; ok { | |
405 | continue | |
406 | } | |
407 | } | |
408 | ||
409 | // Add this to the removed list | |
410 | removed[r.Value] = struct{}{} | |
411 | ||
412 | switch v := r.Value.(type) { | |
413 | case *ModuleState: | |
414 | s.removeModule(path, v) | |
415 | case *ResourceState: | |
416 | s.removeResource(path, v) | |
417 | case *InstanceState: | |
418 | s.removeInstance(path, r.Parent.Value.(*ResourceState), v) | |
419 | default: | |
420 | return fmt.Errorf("unknown type to delete: %T", r.Value) | |
421 | } | |
422 | } | |
423 | ||
424 | // Prune since the removal functions often do the bare minimum to | |
425 | // remove a thing and may leave around dangling empty modules, resources, | |
426 | // etc. Prune will clean that all up. | |
427 | s.prune() | |
428 | ||
429 | return nil | |
430 | } | |
431 | ||
432 | func (s *State) removeModule(path []string, v *ModuleState) { | |
433 | for i, m := range s.Modules { | |
434 | if m == v { | |
435 | s.Modules, s.Modules[len(s.Modules)-1] = append(s.Modules[:i], s.Modules[i+1:]...), nil | |
436 | return | |
437 | } | |
438 | } | |
439 | } | |
440 | ||
441 | func (s *State) removeResource(path []string, v *ResourceState) { | |
442 | // Get the module this resource lives in. If it doesn't exist, we're done. | |
443 | mod := s.moduleByPath(path) | |
444 | if mod == nil { | |
445 | return | |
446 | } | |
447 | ||
448 | // Find this resource. This is a O(N) lookup when if we had the key | |
449 | // it could be O(1) but even with thousands of resources this shouldn't | |
450 | // matter right now. We can easily up performance here when the time comes. | |
451 | for k, r := range mod.Resources { | |
452 | if r == v { | |
453 | // Found it | |
454 | delete(mod.Resources, k) | |
455 | return | |
456 | } | |
457 | } | |
458 | } | |
459 | ||
460 | func (s *State) removeInstance(path []string, r *ResourceState, v *InstanceState) { | |
461 | // Go through the resource and find the instance that matches this | |
462 | // (if any) and remove it. | |
463 | ||
464 | // Check primary | |
465 | if r.Primary == v { | |
466 | r.Primary = nil | |
467 | return | |
468 | } | |
469 | ||
470 | // Check lists | |
471 | lists := [][]*InstanceState{r.Deposed} | |
472 | for _, is := range lists { | |
473 | for i, instance := range is { | |
474 | if instance == v { | |
475 | // Found it, remove it | |
476 | is, is[len(is)-1] = append(is[:i], is[i+1:]...), nil | |
477 | ||
478 | // Done | |
479 | return | |
480 | } | |
481 | } | |
482 | } | |
483 | } | |
484 | ||
485 | // RootModule returns the ModuleState for the root module | |
486 | func (s *State) RootModule() *ModuleState { | |
487 | root := s.ModuleByPath(rootModulePath) | |
488 | if root == nil { | |
489 | panic("missing root module") | |
490 | } | |
491 | return root | |
492 | } | |
493 | ||
494 | // Equal tests if one state is equal to another. | |
495 | func (s *State) Equal(other *State) bool { | |
496 | // If one is nil, we do a direct check | |
497 | if s == nil || other == nil { | |
498 | return s == other | |
499 | } | |
500 | ||
501 | s.Lock() | |
502 | defer s.Unlock() | |
503 | return s.equal(other) | |
504 | } | |
505 | ||
506 | func (s *State) equal(other *State) bool { | |
507 | if s == nil || other == nil { | |
508 | return s == other | |
509 | } | |
510 | ||
511 | // If the versions are different, they're certainly not equal | |
512 | if s.Version != other.Version { | |
513 | return false | |
514 | } | |
515 | ||
516 | // If any of the modules are not equal, then this state isn't equal | |
517 | if len(s.Modules) != len(other.Modules) { | |
518 | return false | |
519 | } | |
520 | for _, m := range s.Modules { | |
521 | // This isn't very optimal currently but works. | |
522 | otherM := other.moduleByPath(m.Path) | |
523 | if otherM == nil { | |
524 | return false | |
525 | } | |
526 | ||
527 | // If they're not equal, then we're not equal! | |
528 | if !m.Equal(otherM) { | |
529 | return false | |
530 | } | |
531 | } | |
532 | ||
533 | return true | |
534 | } | |
535 | ||
c680a8e1 RS |
536 | // MarshalEqual is similar to Equal but provides a stronger definition of |
537 | // "equal", where two states are equal if and only if their serialized form | |
538 | // is byte-for-byte identical. | |
539 | // | |
540 | // This is primarily useful for callers that are trying to save snapshots | |
541 | // of state to persistent storage, allowing them to detect when a new | |
542 | // snapshot must be taken. | |
543 | // | |
544 | // Note that the serial number and lineage are included in the serialized form, | |
545 | // so it's the caller's responsibility to properly manage these attributes | |
546 | // so that this method is only called on two states that have the same | |
547 | // serial and lineage, unless detecting such differences is desired. | |
548 | func (s *State) MarshalEqual(other *State) bool { | |
549 | if s == nil && other == nil { | |
550 | return true | |
551 | } else if s == nil || other == nil { | |
552 | return false | |
553 | } | |
554 | ||
555 | recvBuf := &bytes.Buffer{} | |
556 | otherBuf := &bytes.Buffer{} | |
557 | ||
558 | err := WriteState(s, recvBuf) | |
559 | if err != nil { | |
560 | // should never happen, since we're writing to a buffer | |
561 | panic(err) | |
562 | } | |
563 | ||
564 | err = WriteState(other, otherBuf) | |
565 | if err != nil { | |
566 | // should never happen, since we're writing to a buffer | |
567 | panic(err) | |
568 | } | |
569 | ||
570 | return bytes.Equal(recvBuf.Bytes(), otherBuf.Bytes()) | |
571 | } | |
572 | ||
bae9f6d2 JC |
573 | type StateAgeComparison int |
574 | ||
575 | const ( | |
576 | StateAgeEqual StateAgeComparison = 0 | |
577 | StateAgeReceiverNewer StateAgeComparison = 1 | |
578 | StateAgeReceiverOlder StateAgeComparison = -1 | |
579 | ) | |
580 | ||
581 | // CompareAges compares one state with another for which is "older". | |
582 | // | |
583 | // This is a simple check using the state's serial, and is thus only as | |
584 | // reliable as the serial itself. In the normal case, only one state | |
585 | // exists for a given combination of lineage/serial, but Terraform | |
586 | // does not guarantee this and so the result of this method should be | |
587 | // used with care. | |
588 | // | |
589 | // Returns an integer that is negative if the receiver is older than | |
590 | // the argument, positive if the converse, and zero if they are equal. | |
591 | // An error is returned if the two states are not of the same lineage, | |
592 | // in which case the integer returned has no meaning. | |
593 | func (s *State) CompareAges(other *State) (StateAgeComparison, error) { | |
594 | // nil states are "older" than actual states | |
595 | switch { | |
596 | case s != nil && other == nil: | |
597 | return StateAgeReceiverNewer, nil | |
598 | case s == nil && other != nil: | |
599 | return StateAgeReceiverOlder, nil | |
600 | case s == nil && other == nil: | |
601 | return StateAgeEqual, nil | |
602 | } | |
603 | ||
604 | if !s.SameLineage(other) { | |
605 | return StateAgeEqual, fmt.Errorf( | |
606 | "can't compare two states of differing lineage", | |
607 | ) | |
608 | } | |
609 | ||
610 | s.Lock() | |
611 | defer s.Unlock() | |
612 | ||
613 | switch { | |
614 | case s.Serial < other.Serial: | |
615 | return StateAgeReceiverOlder, nil | |
616 | case s.Serial > other.Serial: | |
617 | return StateAgeReceiverNewer, nil | |
618 | default: | |
619 | return StateAgeEqual, nil | |
620 | } | |
621 | } | |
622 | ||
623 | // SameLineage returns true only if the state given in argument belongs | |
624 | // to the same "lineage" of states as the receiver. | |
625 | func (s *State) SameLineage(other *State) bool { | |
626 | s.Lock() | |
627 | defer s.Unlock() | |
628 | ||
629 | // If one of the states has no lineage then it is assumed to predate | |
630 | // this concept, and so we'll accept it as belonging to any lineage | |
631 | // so that a lineage string can be assigned to newer versions | |
632 | // without breaking compatibility with older versions. | |
633 | if s.Lineage == "" || other.Lineage == "" { | |
634 | return true | |
635 | } | |
636 | ||
637 | return s.Lineage == other.Lineage | |
638 | } | |
639 | ||
640 | // DeepCopy performs a deep copy of the state structure and returns | |
641 | // a new structure. | |
642 | func (s *State) DeepCopy() *State { | |
c680a8e1 RS |
643 | if s == nil { |
644 | return nil | |
645 | } | |
646 | ||
bae9f6d2 JC |
647 | copy, err := copystructure.Config{Lock: true}.Copy(s) |
648 | if err != nil { | |
649 | panic(err) | |
650 | } | |
651 | ||
652 | return copy.(*State) | |
653 | } | |
654 | ||
bae9f6d2 JC |
655 | // FromFutureTerraform checks if this state was written by a Terraform |
656 | // version from the future. | |
657 | func (s *State) FromFutureTerraform() bool { | |
658 | s.Lock() | |
659 | defer s.Unlock() | |
660 | ||
661 | // No TF version means it is certainly from the past | |
662 | if s.TFVersion == "" { | |
663 | return false | |
664 | } | |
665 | ||
666 | v := version.Must(version.NewVersion(s.TFVersion)) | |
667 | return SemVersion.LessThan(v) | |
668 | } | |
669 | ||
670 | func (s *State) Init() { | |
671 | s.Lock() | |
672 | defer s.Unlock() | |
673 | s.init() | |
674 | } | |
675 | ||
676 | func (s *State) init() { | |
677 | if s.Version == 0 { | |
678 | s.Version = StateVersion | |
679 | } | |
c680a8e1 | 680 | |
bae9f6d2 JC |
681 | if s.moduleByPath(rootModulePath) == nil { |
682 | s.addModule(rootModulePath) | |
683 | } | |
684 | s.ensureHasLineage() | |
685 | ||
686 | for _, mod := range s.Modules { | |
687 | if mod != nil { | |
688 | mod.init() | |
689 | } | |
690 | } | |
691 | ||
692 | if s.Remote != nil { | |
693 | s.Remote.init() | |
694 | } | |
695 | ||
696 | } | |
697 | ||
698 | func (s *State) EnsureHasLineage() { | |
699 | s.Lock() | |
700 | defer s.Unlock() | |
701 | ||
702 | s.ensureHasLineage() | |
703 | } | |
704 | ||
705 | func (s *State) ensureHasLineage() { | |
706 | if s.Lineage == "" { | |
707 | s.Lineage = uuid.NewV4().String() | |
708 | log.Printf("[DEBUG] New state was assigned lineage %q\n", s.Lineage) | |
709 | } else { | |
710 | log.Printf("[TRACE] Preserving existing state lineage %q\n", s.Lineage) | |
711 | } | |
712 | } | |
713 | ||
714 | // AddModuleState insert this module state and override any existing ModuleState | |
715 | func (s *State) AddModuleState(mod *ModuleState) { | |
716 | mod.init() | |
717 | s.Lock() | |
718 | defer s.Unlock() | |
719 | ||
720 | s.addModuleState(mod) | |
721 | } | |
722 | ||
723 | func (s *State) addModuleState(mod *ModuleState) { | |
724 | for i, m := range s.Modules { | |
725 | if reflect.DeepEqual(m.Path, mod.Path) { | |
726 | s.Modules[i] = mod | |
727 | return | |
728 | } | |
729 | } | |
730 | ||
731 | s.Modules = append(s.Modules, mod) | |
732 | s.sort() | |
733 | } | |
734 | ||
735 | // prune is used to remove any resources that are no longer required | |
736 | func (s *State) prune() { | |
737 | if s == nil { | |
738 | return | |
739 | } | |
740 | ||
741 | // Filter out empty modules. | |
742 | // A module is always assumed to have a path, and it's length isn't always | |
743 | // bounds checked later on. Modules may be "emptied" during destroy, but we | |
744 | // never want to store those in the state. | |
745 | for i := 0; i < len(s.Modules); i++ { | |
746 | if s.Modules[i] == nil || len(s.Modules[i].Path) == 0 { | |
747 | s.Modules = append(s.Modules[:i], s.Modules[i+1:]...) | |
748 | i-- | |
749 | } | |
750 | } | |
751 | ||
752 | for _, mod := range s.Modules { | |
753 | mod.prune() | |
754 | } | |
755 | if s.Remote != nil && s.Remote.Empty() { | |
756 | s.Remote = nil | |
757 | } | |
758 | } | |
759 | ||
760 | // sort sorts the modules | |
761 | func (s *State) sort() { | |
762 | sort.Sort(moduleStateSort(s.Modules)) | |
763 | ||
764 | // Allow modules to be sorted | |
765 | for _, m := range s.Modules { | |
766 | if m != nil { | |
767 | m.sort() | |
768 | } | |
769 | } | |
770 | } | |
771 | ||
772 | func (s *State) String() string { | |
773 | if s == nil { | |
774 | return "<nil>" | |
775 | } | |
776 | s.Lock() | |
777 | defer s.Unlock() | |
778 | ||
779 | var buf bytes.Buffer | |
780 | for _, m := range s.Modules { | |
781 | mStr := m.String() | |
782 | ||
783 | // If we're the root module, we just write the output directly. | |
784 | if reflect.DeepEqual(m.Path, rootModulePath) { | |
785 | buf.WriteString(mStr + "\n") | |
786 | continue | |
787 | } | |
788 | ||
789 | buf.WriteString(fmt.Sprintf("module.%s:\n", strings.Join(m.Path[1:], "."))) | |
790 | ||
791 | s := bufio.NewScanner(strings.NewReader(mStr)) | |
792 | for s.Scan() { | |
793 | text := s.Text() | |
794 | if text != "" { | |
795 | text = " " + text | |
796 | } | |
797 | ||
798 | buf.WriteString(fmt.Sprintf("%s\n", text)) | |
799 | } | |
800 | } | |
801 | ||
802 | return strings.TrimSpace(buf.String()) | |
803 | } | |
804 | ||
805 | // BackendState stores the configuration to connect to a remote backend. | |
806 | type BackendState struct { | |
807 | Type string `json:"type"` // Backend type | |
808 | Config map[string]interface{} `json:"config"` // Backend raw config | |
809 | ||
810 | // Hash is the hash code to uniquely identify the original source | |
811 | // configuration. We use this to detect when there is a change in | |
812 | // configuration even when "type" isn't changed. | |
813 | Hash uint64 `json:"hash"` | |
814 | } | |
815 | ||
816 | // Empty returns true if BackendState has no state. | |
817 | func (s *BackendState) Empty() bool { | |
818 | return s == nil || s.Type == "" | |
819 | } | |
820 | ||
821 | // Rehash returns a unique content hash for this backend's configuration | |
822 | // as a uint64 value. | |
823 | // The Hash stored in the backend state needs to match the config itself, but | |
824 | // we need to compare the backend config after it has been combined with all | |
825 | // options. | |
826 | // This function must match the implementation used by config.Backend. | |
827 | func (s *BackendState) Rehash() uint64 { | |
828 | if s == nil { | |
829 | return 0 | |
830 | } | |
831 | ||
832 | cfg := config.Backend{ | |
833 | Type: s.Type, | |
834 | RawConfig: &config.RawConfig{ | |
835 | Raw: s.Config, | |
836 | }, | |
837 | } | |
838 | ||
839 | return cfg.Rehash() | |
840 | } | |
841 | ||
842 | // RemoteState is used to track the information about a remote | |
843 | // state store that we push/pull state to. | |
844 | type RemoteState struct { | |
845 | // Type controls the client we use for the remote state | |
846 | Type string `json:"type"` | |
847 | ||
848 | // Config is used to store arbitrary configuration that | |
849 | // is type specific | |
850 | Config map[string]string `json:"config"` | |
851 | ||
852 | mu sync.Mutex | |
853 | } | |
854 | ||
855 | func (s *RemoteState) Lock() { s.mu.Lock() } | |
856 | func (s *RemoteState) Unlock() { s.mu.Unlock() } | |
857 | ||
858 | func (r *RemoteState) init() { | |
859 | r.Lock() | |
860 | defer r.Unlock() | |
861 | ||
862 | if r.Config == nil { | |
863 | r.Config = make(map[string]string) | |
864 | } | |
865 | } | |
866 | ||
867 | func (r *RemoteState) deepcopy() *RemoteState { | |
868 | r.Lock() | |
869 | defer r.Unlock() | |
870 | ||
871 | confCopy := make(map[string]string, len(r.Config)) | |
872 | for k, v := range r.Config { | |
873 | confCopy[k] = v | |
874 | } | |
875 | return &RemoteState{ | |
876 | Type: r.Type, | |
877 | Config: confCopy, | |
878 | } | |
879 | } | |
880 | ||
881 | func (r *RemoteState) Empty() bool { | |
882 | if r == nil { | |
883 | return true | |
884 | } | |
885 | r.Lock() | |
886 | defer r.Unlock() | |
887 | ||
888 | return r.Type == "" | |
889 | } | |
890 | ||
891 | func (r *RemoteState) Equals(other *RemoteState) bool { | |
892 | r.Lock() | |
893 | defer r.Unlock() | |
894 | ||
895 | if r.Type != other.Type { | |
896 | return false | |
897 | } | |
898 | if len(r.Config) != len(other.Config) { | |
899 | return false | |
900 | } | |
901 | for k, v := range r.Config { | |
902 | if other.Config[k] != v { | |
903 | return false | |
904 | } | |
905 | } | |
906 | return true | |
907 | } | |
908 | ||
909 | // OutputState is used to track the state relevant to a single output. | |
910 | type OutputState struct { | |
911 | // Sensitive describes whether the output is considered sensitive, | |
912 | // which may lead to masking the value on screen in some cases. | |
913 | Sensitive bool `json:"sensitive"` | |
914 | // Type describes the structure of Value. Valid values are "string", | |
915 | // "map" and "list" | |
916 | Type string `json:"type"` | |
917 | // Value contains the value of the output, in the structure described | |
918 | // by the Type field. | |
919 | Value interface{} `json:"value"` | |
920 | ||
921 | mu sync.Mutex | |
922 | } | |
923 | ||
924 | func (s *OutputState) Lock() { s.mu.Lock() } | |
925 | func (s *OutputState) Unlock() { s.mu.Unlock() } | |
926 | ||
927 | func (s *OutputState) String() string { | |
928 | return fmt.Sprintf("%#v", s.Value) | |
929 | } | |
930 | ||
931 | // Equal compares two OutputState structures for equality. nil values are | |
932 | // considered equal. | |
933 | func (s *OutputState) Equal(other *OutputState) bool { | |
934 | if s == nil && other == nil { | |
935 | return true | |
936 | } | |
937 | ||
938 | if s == nil || other == nil { | |
939 | return false | |
940 | } | |
941 | s.Lock() | |
942 | defer s.Unlock() | |
943 | ||
944 | if s.Type != other.Type { | |
945 | return false | |
946 | } | |
947 | ||
948 | if s.Sensitive != other.Sensitive { | |
949 | return false | |
950 | } | |
951 | ||
952 | if !reflect.DeepEqual(s.Value, other.Value) { | |
953 | return false | |
954 | } | |
955 | ||
956 | return true | |
957 | } | |
958 | ||
959 | func (s *OutputState) deepcopy() *OutputState { | |
960 | if s == nil { | |
961 | return nil | |
962 | } | |
963 | ||
964 | stateCopy, err := copystructure.Config{Lock: true}.Copy(s) | |
965 | if err != nil { | |
966 | panic(fmt.Errorf("Error copying output value: %s", err)) | |
967 | } | |
968 | ||
969 | return stateCopy.(*OutputState) | |
970 | } | |
971 | ||
972 | // ModuleState is used to track all the state relevant to a single | |
973 | // module. Previous to Terraform 0.3, all state belonged to the "root" | |
974 | // module. | |
975 | type ModuleState struct { | |
976 | // Path is the import path from the root module. Modules imports are | |
977 | // always disjoint, so the path represents amodule tree | |
978 | Path []string `json:"path"` | |
979 | ||
980 | // Outputs declared by the module and maintained for each module | |
981 | // even though only the root module technically needs to be kept. | |
982 | // This allows operators to inspect values at the boundaries. | |
983 | Outputs map[string]*OutputState `json:"outputs"` | |
984 | ||
985 | // Resources is a mapping of the logically named resource to | |
986 | // the state of the resource. Each resource may actually have | |
987 | // N instances underneath, although a user only needs to think | |
988 | // about the 1:1 case. | |
989 | Resources map[string]*ResourceState `json:"resources"` | |
990 | ||
991 | // Dependencies are a list of things that this module relies on | |
992 | // existing to remain intact. For example: an module may depend | |
993 | // on a VPC ID given by an aws_vpc resource. | |
994 | // | |
995 | // Terraform uses this information to build valid destruction | |
996 | // orders and to warn the user if they're destroying a module that | |
997 | // another resource depends on. | |
998 | // | |
999 | // Things can be put into this list that may not be managed by | |
1000 | // Terraform. If Terraform doesn't find a matching ID in the | |
1001 | // overall state, then it assumes it isn't managed and doesn't | |
1002 | // worry about it. | |
1003 | Dependencies []string `json:"depends_on"` | |
1004 | ||
1005 | mu sync.Mutex | |
1006 | } | |
1007 | ||
1008 | func (s *ModuleState) Lock() { s.mu.Lock() } | |
1009 | func (s *ModuleState) Unlock() { s.mu.Unlock() } | |
1010 | ||
1011 | // Equal tests whether one module state is equal to another. | |
1012 | func (m *ModuleState) Equal(other *ModuleState) bool { | |
1013 | m.Lock() | |
1014 | defer m.Unlock() | |
1015 | ||
1016 | // Paths must be equal | |
1017 | if !reflect.DeepEqual(m.Path, other.Path) { | |
1018 | return false | |
1019 | } | |
1020 | ||
1021 | // Outputs must be equal | |
1022 | if len(m.Outputs) != len(other.Outputs) { | |
1023 | return false | |
1024 | } | |
1025 | for k, v := range m.Outputs { | |
1026 | if !other.Outputs[k].Equal(v) { | |
1027 | return false | |
1028 | } | |
1029 | } | |
1030 | ||
1031 | // Dependencies must be equal. This sorts these in place but | |
1032 | // this shouldn't cause any problems. | |
1033 | sort.Strings(m.Dependencies) | |
1034 | sort.Strings(other.Dependencies) | |
1035 | if len(m.Dependencies) != len(other.Dependencies) { | |
1036 | return false | |
1037 | } | |
1038 | for i, d := range m.Dependencies { | |
1039 | if other.Dependencies[i] != d { | |
1040 | return false | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | // Resources must be equal | |
1045 | if len(m.Resources) != len(other.Resources) { | |
1046 | return false | |
1047 | } | |
1048 | for k, r := range m.Resources { | |
1049 | otherR, ok := other.Resources[k] | |
1050 | if !ok { | |
1051 | return false | |
1052 | } | |
1053 | ||
1054 | if !r.Equal(otherR) { | |
1055 | return false | |
1056 | } | |
1057 | } | |
1058 | ||
1059 | return true | |
1060 | } | |
1061 | ||
1062 | // IsRoot says whether or not this module diff is for the root module. | |
1063 | func (m *ModuleState) IsRoot() bool { | |
1064 | m.Lock() | |
1065 | defer m.Unlock() | |
1066 | return reflect.DeepEqual(m.Path, rootModulePath) | |
1067 | } | |
1068 | ||
1069 | // IsDescendent returns true if other is a descendent of this module. | |
1070 | func (m *ModuleState) IsDescendent(other *ModuleState) bool { | |
1071 | m.Lock() | |
1072 | defer m.Unlock() | |
1073 | ||
1074 | i := len(m.Path) | |
1075 | return len(other.Path) > i && reflect.DeepEqual(other.Path[:i], m.Path) | |
1076 | } | |
1077 | ||
1078 | // Orphans returns a list of keys of resources that are in the State | |
1079 | // but aren't present in the configuration itself. Hence, these keys | |
1080 | // represent the state of resources that are orphans. | |
1081 | func (m *ModuleState) Orphans(c *config.Config) []string { | |
1082 | m.Lock() | |
1083 | defer m.Unlock() | |
1084 | ||
1085 | keys := make(map[string]struct{}) | |
1086 | for k, _ := range m.Resources { | |
1087 | keys[k] = struct{}{} | |
1088 | } | |
1089 | ||
1090 | if c != nil { | |
1091 | for _, r := range c.Resources { | |
1092 | delete(keys, r.Id()) | |
1093 | ||
1094 | for k, _ := range keys { | |
1095 | if strings.HasPrefix(k, r.Id()+".") { | |
1096 | delete(keys, k) | |
1097 | } | |
1098 | } | |
1099 | } | |
1100 | } | |
1101 | ||
1102 | result := make([]string, 0, len(keys)) | |
1103 | for k, _ := range keys { | |
1104 | result = append(result, k) | |
1105 | } | |
1106 | ||
1107 | return result | |
1108 | } | |
1109 | ||
1110 | // View returns a view with the given resource prefix. | |
1111 | func (m *ModuleState) View(id string) *ModuleState { | |
1112 | if m == nil { | |
1113 | return m | |
1114 | } | |
1115 | ||
1116 | r := m.deepcopy() | |
1117 | for k, _ := range r.Resources { | |
1118 | if id == k || strings.HasPrefix(k, id+".") { | |
1119 | continue | |
1120 | } | |
1121 | ||
1122 | delete(r.Resources, k) | |
1123 | } | |
1124 | ||
1125 | return r | |
1126 | } | |
1127 | ||
1128 | func (m *ModuleState) init() { | |
1129 | m.Lock() | |
1130 | defer m.Unlock() | |
1131 | ||
1132 | if m.Path == nil { | |
1133 | m.Path = []string{} | |
1134 | } | |
1135 | if m.Outputs == nil { | |
1136 | m.Outputs = make(map[string]*OutputState) | |
1137 | } | |
1138 | if m.Resources == nil { | |
1139 | m.Resources = make(map[string]*ResourceState) | |
1140 | } | |
1141 | ||
1142 | if m.Dependencies == nil { | |
1143 | m.Dependencies = make([]string, 0) | |
1144 | } | |
1145 | ||
1146 | for _, rs := range m.Resources { | |
1147 | rs.init() | |
1148 | } | |
1149 | } | |
1150 | ||
1151 | func (m *ModuleState) deepcopy() *ModuleState { | |
1152 | if m == nil { | |
1153 | return nil | |
1154 | } | |
1155 | ||
1156 | stateCopy, err := copystructure.Config{Lock: true}.Copy(m) | |
1157 | if err != nil { | |
1158 | panic(err) | |
1159 | } | |
1160 | ||
1161 | return stateCopy.(*ModuleState) | |
1162 | } | |
1163 | ||
1164 | // prune is used to remove any resources that are no longer required | |
1165 | func (m *ModuleState) prune() { | |
1166 | m.Lock() | |
1167 | defer m.Unlock() | |
1168 | ||
1169 | for k, v := range m.Resources { | |
1170 | if v == nil || (v.Primary == nil || v.Primary.ID == "") && len(v.Deposed) == 0 { | |
1171 | delete(m.Resources, k) | |
1172 | continue | |
1173 | } | |
1174 | ||
1175 | v.prune() | |
1176 | } | |
1177 | ||
1178 | for k, v := range m.Outputs { | |
1179 | if v.Value == config.UnknownVariableValue { | |
1180 | delete(m.Outputs, k) | |
1181 | } | |
1182 | } | |
1183 | ||
1184 | m.Dependencies = uniqueStrings(m.Dependencies) | |
1185 | } | |
1186 | ||
1187 | func (m *ModuleState) sort() { | |
1188 | for _, v := range m.Resources { | |
1189 | v.sort() | |
1190 | } | |
1191 | } | |
1192 | ||
1193 | func (m *ModuleState) String() string { | |
1194 | m.Lock() | |
1195 | defer m.Unlock() | |
1196 | ||
1197 | var buf bytes.Buffer | |
1198 | ||
1199 | if len(m.Resources) == 0 { | |
1200 | buf.WriteString("<no state>") | |
1201 | } | |
1202 | ||
1203 | names := make([]string, 0, len(m.Resources)) | |
1204 | for name, _ := range m.Resources { | |
1205 | names = append(names, name) | |
1206 | } | |
1207 | ||
1208 | sort.Sort(resourceNameSort(names)) | |
1209 | ||
1210 | for _, k := range names { | |
1211 | rs := m.Resources[k] | |
1212 | var id string | |
1213 | if rs.Primary != nil { | |
1214 | id = rs.Primary.ID | |
1215 | } | |
1216 | if id == "" { | |
1217 | id = "<not created>" | |
1218 | } | |
1219 | ||
1220 | taintStr := "" | |
1221 | if rs.Primary.Tainted { | |
1222 | taintStr = " (tainted)" | |
1223 | } | |
1224 | ||
1225 | deposedStr := "" | |
1226 | if len(rs.Deposed) > 0 { | |
1227 | deposedStr = fmt.Sprintf(" (%d deposed)", len(rs.Deposed)) | |
1228 | } | |
1229 | ||
1230 | buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr)) | |
1231 | buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) | |
1232 | if rs.Provider != "" { | |
1233 | buf.WriteString(fmt.Sprintf(" provider = %s\n", rs.Provider)) | |
1234 | } | |
1235 | ||
1236 | var attributes map[string]string | |
1237 | if rs.Primary != nil { | |
1238 | attributes = rs.Primary.Attributes | |
1239 | } | |
1240 | attrKeys := make([]string, 0, len(attributes)) | |
1241 | for ak, _ := range attributes { | |
1242 | if ak == "id" { | |
1243 | continue | |
1244 | } | |
1245 | ||
1246 | attrKeys = append(attrKeys, ak) | |
1247 | } | |
1248 | ||
1249 | sort.Strings(attrKeys) | |
1250 | ||
1251 | for _, ak := range attrKeys { | |
1252 | av := attributes[ak] | |
1253 | buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) | |
1254 | } | |
1255 | ||
1256 | for idx, t := range rs.Deposed { | |
1257 | taintStr := "" | |
1258 | if t.Tainted { | |
1259 | taintStr = " (tainted)" | |
1260 | } | |
1261 | buf.WriteString(fmt.Sprintf(" Deposed ID %d = %s%s\n", idx+1, t.ID, taintStr)) | |
1262 | } | |
1263 | ||
1264 | if len(rs.Dependencies) > 0 { | |
1265 | buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) | |
1266 | for _, dep := range rs.Dependencies { | |
1267 | buf.WriteString(fmt.Sprintf(" %s\n", dep)) | |
1268 | } | |
1269 | } | |
1270 | } | |
1271 | ||
1272 | if len(m.Outputs) > 0 { | |
1273 | buf.WriteString("\nOutputs:\n\n") | |
1274 | ||
1275 | ks := make([]string, 0, len(m.Outputs)) | |
1276 | for k, _ := range m.Outputs { | |
1277 | ks = append(ks, k) | |
1278 | } | |
1279 | ||
1280 | sort.Strings(ks) | |
1281 | ||
1282 | for _, k := range ks { | |
1283 | v := m.Outputs[k] | |
1284 | switch vTyped := v.Value.(type) { | |
1285 | case string: | |
1286 | buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped)) | |
1287 | case []interface{}: | |
1288 | buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped)) | |
1289 | case map[string]interface{}: | |
1290 | var mapKeys []string | |
1291 | for key, _ := range vTyped { | |
1292 | mapKeys = append(mapKeys, key) | |
1293 | } | |
1294 | sort.Strings(mapKeys) | |
1295 | ||
1296 | var mapBuf bytes.Buffer | |
1297 | mapBuf.WriteString("{") | |
1298 | for _, key := range mapKeys { | |
1299 | mapBuf.WriteString(fmt.Sprintf("%s:%s ", key, vTyped[key])) | |
1300 | } | |
1301 | mapBuf.WriteString("}") | |
1302 | ||
1303 | buf.WriteString(fmt.Sprintf("%s = %s\n", k, mapBuf.String())) | |
1304 | } | |
1305 | } | |
1306 | } | |
1307 | ||
1308 | return buf.String() | |
1309 | } | |
1310 | ||
1311 | // ResourceStateKey is a structured representation of the key used for the | |
1312 | // ModuleState.Resources mapping | |
1313 | type ResourceStateKey struct { | |
1314 | Name string | |
1315 | Type string | |
1316 | Mode config.ResourceMode | |
1317 | Index int | |
1318 | } | |
1319 | ||
1320 | // Equal determines whether two ResourceStateKeys are the same | |
1321 | func (rsk *ResourceStateKey) Equal(other *ResourceStateKey) bool { | |
1322 | if rsk == nil || other == nil { | |
1323 | return false | |
1324 | } | |
1325 | if rsk.Mode != other.Mode { | |
1326 | return false | |
1327 | } | |
1328 | if rsk.Type != other.Type { | |
1329 | return false | |
1330 | } | |
1331 | if rsk.Name != other.Name { | |
1332 | return false | |
1333 | } | |
1334 | if rsk.Index != other.Index { | |
1335 | return false | |
1336 | } | |
1337 | return true | |
1338 | } | |
1339 | ||
1340 | func (rsk *ResourceStateKey) String() string { | |
1341 | if rsk == nil { | |
1342 | return "" | |
1343 | } | |
1344 | var prefix string | |
1345 | switch rsk.Mode { | |
1346 | case config.ManagedResourceMode: | |
1347 | prefix = "" | |
1348 | case config.DataResourceMode: | |
1349 | prefix = "data." | |
1350 | default: | |
1351 | panic(fmt.Errorf("unknown resource mode %s", rsk.Mode)) | |
1352 | } | |
1353 | if rsk.Index == -1 { | |
1354 | return fmt.Sprintf("%s%s.%s", prefix, rsk.Type, rsk.Name) | |
1355 | } | |
1356 | return fmt.Sprintf("%s%s.%s.%d", prefix, rsk.Type, rsk.Name, rsk.Index) | |
1357 | } | |
1358 | ||
1359 | // ParseResourceStateKey accepts a key in the format used by | |
1360 | // ModuleState.Resources and returns a resource name and resource index. In the | |
1361 | // state, a resource has the format "type.name.index" or "type.name". In the | |
1362 | // latter case, the index is returned as -1. | |
1363 | func ParseResourceStateKey(k string) (*ResourceStateKey, error) { | |
1364 | parts := strings.Split(k, ".") | |
1365 | mode := config.ManagedResourceMode | |
1366 | if len(parts) > 0 && parts[0] == "data" { | |
1367 | mode = config.DataResourceMode | |
1368 | // Don't need the constant "data" prefix for parsing | |
1369 | // now that we've figured out the mode. | |
1370 | parts = parts[1:] | |
1371 | } | |
1372 | if len(parts) < 2 || len(parts) > 3 { | |
1373 | return nil, fmt.Errorf("Malformed resource state key: %s", k) | |
1374 | } | |
1375 | rsk := &ResourceStateKey{ | |
1376 | Mode: mode, | |
1377 | Type: parts[0], | |
1378 | Name: parts[1], | |
1379 | Index: -1, | |
1380 | } | |
1381 | if len(parts) == 3 { | |
1382 | index, err := strconv.Atoi(parts[2]) | |
1383 | if err != nil { | |
1384 | return nil, fmt.Errorf("Malformed resource state key index: %s", k) | |
1385 | } | |
1386 | rsk.Index = index | |
1387 | } | |
1388 | return rsk, nil | |
1389 | } | |
1390 | ||
1391 | // ResourceState holds the state of a resource that is used so that | |
1392 | // a provider can find and manage an existing resource as well as for | |
1393 | // storing attributes that are used to populate variables of child | |
1394 | // resources. | |
1395 | // | |
1396 | // Attributes has attributes about the created resource that are | |
1397 | // queryable in interpolation: "${type.id.attr}" | |
1398 | // | |
1399 | // Extra is just extra data that a provider can return that we store | |
1400 | // for later, but is not exposed in any way to the user. | |
1401 | // | |
1402 | type ResourceState struct { | |
1403 | // This is filled in and managed by Terraform, and is the resource | |
1404 | // type itself such as "mycloud_instance". If a resource provider sets | |
1405 | // this value, it won't be persisted. | |
1406 | Type string `json:"type"` | |
1407 | ||
1408 | // Dependencies are a list of things that this resource relies on | |
1409 | // existing to remain intact. For example: an AWS instance might | |
1410 | // depend on a subnet (which itself might depend on a VPC, and so | |
1411 | // on). | |
1412 | // | |
1413 | // Terraform uses this information to build valid destruction | |
1414 | // orders and to warn the user if they're destroying a resource that | |
1415 | // another resource depends on. | |
1416 | // | |
1417 | // Things can be put into this list that may not be managed by | |
1418 | // Terraform. If Terraform doesn't find a matching ID in the | |
1419 | // overall state, then it assumes it isn't managed and doesn't | |
1420 | // worry about it. | |
1421 | Dependencies []string `json:"depends_on"` | |
1422 | ||
1423 | // Primary is the current active instance for this resource. | |
1424 | // It can be replaced but only after a successful creation. | |
1425 | // This is the instances on which providers will act. | |
1426 | Primary *InstanceState `json:"primary"` | |
1427 | ||
1428 | // Deposed is used in the mechanics of CreateBeforeDestroy: the existing | |
1429 | // Primary is Deposed to get it out of the way for the replacement Primary to | |
1430 | // be created by Apply. If the replacement Primary creates successfully, the | |
1431 | // Deposed instance is cleaned up. | |
1432 | // | |
1433 | // If there were problems creating the replacement Primary, the Deposed | |
1434 | // instance and the (now tainted) replacement Primary will be swapped so the | |
1435 | // tainted replacement will be cleaned up instead. | |
1436 | // | |
1437 | // An instance will remain in the Deposed list until it is successfully | |
1438 | // destroyed and purged. | |
1439 | Deposed []*InstanceState `json:"deposed"` | |
1440 | ||
1441 | // Provider is used when a resource is connected to a provider with an alias. | |
1442 | // If this string is empty, the resource is connected to the default provider, | |
1443 | // e.g. "aws_instance" goes with the "aws" provider. | |
1444 | // If the resource block contained a "provider" key, that value will be set here. | |
1445 | Provider string `json:"provider"` | |
1446 | ||
1447 | mu sync.Mutex | |
1448 | } | |
1449 | ||
1450 | func (s *ResourceState) Lock() { s.mu.Lock() } | |
1451 | func (s *ResourceState) Unlock() { s.mu.Unlock() } | |
1452 | ||
1453 | // Equal tests whether two ResourceStates are equal. | |
1454 | func (s *ResourceState) Equal(other *ResourceState) bool { | |
1455 | s.Lock() | |
1456 | defer s.Unlock() | |
1457 | ||
1458 | if s.Type != other.Type { | |
1459 | return false | |
1460 | } | |
1461 | ||
1462 | if s.Provider != other.Provider { | |
1463 | return false | |
1464 | } | |
1465 | ||
1466 | // Dependencies must be equal | |
1467 | sort.Strings(s.Dependencies) | |
1468 | sort.Strings(other.Dependencies) | |
1469 | if len(s.Dependencies) != len(other.Dependencies) { | |
1470 | return false | |
1471 | } | |
1472 | for i, d := range s.Dependencies { | |
1473 | if other.Dependencies[i] != d { | |
1474 | return false | |
1475 | } | |
1476 | } | |
1477 | ||
1478 | // States must be equal | |
1479 | if !s.Primary.Equal(other.Primary) { | |
1480 | return false | |
1481 | } | |
1482 | ||
1483 | return true | |
1484 | } | |
1485 | ||
1486 | // Taint marks a resource as tainted. | |
1487 | func (s *ResourceState) Taint() { | |
1488 | s.Lock() | |
1489 | defer s.Unlock() | |
1490 | ||
1491 | if s.Primary != nil { | |
1492 | s.Primary.Tainted = true | |
1493 | } | |
1494 | } | |
1495 | ||
1496 | // Untaint unmarks a resource as tainted. | |
1497 | func (s *ResourceState) Untaint() { | |
1498 | s.Lock() | |
1499 | defer s.Unlock() | |
1500 | ||
1501 | if s.Primary != nil { | |
1502 | s.Primary.Tainted = false | |
1503 | } | |
1504 | } | |
1505 | ||
1506 | func (s *ResourceState) init() { | |
1507 | s.Lock() | |
1508 | defer s.Unlock() | |
1509 | ||
1510 | if s.Primary == nil { | |
1511 | s.Primary = &InstanceState{} | |
1512 | } | |
1513 | s.Primary.init() | |
1514 | ||
1515 | if s.Dependencies == nil { | |
1516 | s.Dependencies = []string{} | |
1517 | } | |
1518 | ||
1519 | if s.Deposed == nil { | |
1520 | s.Deposed = make([]*InstanceState, 0) | |
1521 | } | |
1522 | } | |
1523 | ||
1524 | func (s *ResourceState) deepcopy() *ResourceState { | |
1525 | copy, err := copystructure.Config{Lock: true}.Copy(s) | |
1526 | if err != nil { | |
1527 | panic(err) | |
1528 | } | |
1529 | ||
1530 | return copy.(*ResourceState) | |
1531 | } | |
1532 | ||
1533 | // prune is used to remove any instances that are no longer required | |
1534 | func (s *ResourceState) prune() { | |
1535 | s.Lock() | |
1536 | defer s.Unlock() | |
1537 | ||
1538 | n := len(s.Deposed) | |
1539 | for i := 0; i < n; i++ { | |
1540 | inst := s.Deposed[i] | |
1541 | if inst == nil || inst.ID == "" { | |
1542 | copy(s.Deposed[i:], s.Deposed[i+1:]) | |
1543 | s.Deposed[n-1] = nil | |
1544 | n-- | |
1545 | i-- | |
1546 | } | |
1547 | } | |
1548 | s.Deposed = s.Deposed[:n] | |
1549 | ||
1550 | s.Dependencies = uniqueStrings(s.Dependencies) | |
1551 | } | |
1552 | ||
1553 | func (s *ResourceState) sort() { | |
1554 | s.Lock() | |
1555 | defer s.Unlock() | |
1556 | ||
1557 | sort.Strings(s.Dependencies) | |
1558 | } | |
1559 | ||
1560 | func (s *ResourceState) String() string { | |
1561 | s.Lock() | |
1562 | defer s.Unlock() | |
1563 | ||
1564 | var buf bytes.Buffer | |
1565 | buf.WriteString(fmt.Sprintf("Type = %s", s.Type)) | |
1566 | return buf.String() | |
1567 | } | |
1568 | ||
1569 | // InstanceState is used to track the unique state information belonging | |
1570 | // to a given instance. | |
1571 | type InstanceState struct { | |
1572 | // A unique ID for this resource. This is opaque to Terraform | |
1573 | // and is only meant as a lookup mechanism for the providers. | |
1574 | ID string `json:"id"` | |
1575 | ||
1576 | // Attributes are basic information about the resource. Any keys here | |
1577 | // are accessible in variable format within Terraform configurations: | |
1578 | // ${resourcetype.name.attribute}. | |
1579 | Attributes map[string]string `json:"attributes"` | |
1580 | ||
1581 | // Ephemeral is used to store any state associated with this instance | |
1582 | // that is necessary for the Terraform run to complete, but is not | |
1583 | // persisted to a state file. | |
1584 | Ephemeral EphemeralState `json:"-"` | |
1585 | ||
1586 | // Meta is a simple K/V map that is persisted to the State but otherwise | |
1587 | // ignored by Terraform core. It's meant to be used for accounting by | |
1588 | // external client code. The value here must only contain Go primitives | |
1589 | // and collections. | |
1590 | Meta map[string]interface{} `json:"meta"` | |
1591 | ||
1592 | // Tainted is used to mark a resource for recreation. | |
1593 | Tainted bool `json:"tainted"` | |
1594 | ||
1595 | mu sync.Mutex | |
1596 | } | |
1597 | ||
1598 | func (s *InstanceState) Lock() { s.mu.Lock() } | |
1599 | func (s *InstanceState) Unlock() { s.mu.Unlock() } | |
1600 | ||
1601 | func (s *InstanceState) init() { | |
1602 | s.Lock() | |
1603 | defer s.Unlock() | |
1604 | ||
1605 | if s.Attributes == nil { | |
1606 | s.Attributes = make(map[string]string) | |
1607 | } | |
1608 | if s.Meta == nil { | |
1609 | s.Meta = make(map[string]interface{}) | |
1610 | } | |
1611 | s.Ephemeral.init() | |
1612 | } | |
1613 | ||
1614 | // Copy all the Fields from another InstanceState | |
1615 | func (s *InstanceState) Set(from *InstanceState) { | |
1616 | s.Lock() | |
1617 | defer s.Unlock() | |
1618 | ||
1619 | from.Lock() | |
1620 | defer from.Unlock() | |
1621 | ||
1622 | s.ID = from.ID | |
1623 | s.Attributes = from.Attributes | |
1624 | s.Ephemeral = from.Ephemeral | |
1625 | s.Meta = from.Meta | |
1626 | s.Tainted = from.Tainted | |
1627 | } | |
1628 | ||
1629 | func (s *InstanceState) DeepCopy() *InstanceState { | |
1630 | copy, err := copystructure.Config{Lock: true}.Copy(s) | |
1631 | if err != nil { | |
1632 | panic(err) | |
1633 | } | |
1634 | ||
1635 | return copy.(*InstanceState) | |
1636 | } | |
1637 | ||
1638 | func (s *InstanceState) Empty() bool { | |
1639 | if s == nil { | |
1640 | return true | |
1641 | } | |
1642 | s.Lock() | |
1643 | defer s.Unlock() | |
1644 | ||
1645 | return s.ID == "" | |
1646 | } | |
1647 | ||
1648 | func (s *InstanceState) Equal(other *InstanceState) bool { | |
1649 | // Short circuit some nil checks | |
1650 | if s == nil || other == nil { | |
1651 | return s == other | |
1652 | } | |
1653 | s.Lock() | |
1654 | defer s.Unlock() | |
1655 | ||
1656 | // IDs must be equal | |
1657 | if s.ID != other.ID { | |
1658 | return false | |
1659 | } | |
1660 | ||
1661 | // Attributes must be equal | |
1662 | if len(s.Attributes) != len(other.Attributes) { | |
1663 | return false | |
1664 | } | |
1665 | for k, v := range s.Attributes { | |
1666 | otherV, ok := other.Attributes[k] | |
1667 | if !ok { | |
1668 | return false | |
1669 | } | |
1670 | ||
1671 | if v != otherV { | |
1672 | return false | |
1673 | } | |
1674 | } | |
1675 | ||
1676 | // Meta must be equal | |
1677 | if len(s.Meta) != len(other.Meta) { | |
1678 | return false | |
1679 | } | |
1680 | if s.Meta != nil && other.Meta != nil { | |
1681 | // We only do the deep check if both are non-nil. If one is nil | |
1682 | // we treat it as equal since their lengths are both zero (check | |
1683 | // above). | |
1684 | if !reflect.DeepEqual(s.Meta, other.Meta) { | |
1685 | return false | |
1686 | } | |
1687 | } | |
1688 | ||
1689 | if s.Tainted != other.Tainted { | |
1690 | return false | |
1691 | } | |
1692 | ||
1693 | return true | |
1694 | } | |
1695 | ||
1696 | // MergeDiff takes a ResourceDiff and merges the attributes into | |
1697 | // this resource state in order to generate a new state. This new | |
1698 | // state can be used to provide updated attribute lookups for | |
1699 | // variable interpolation. | |
1700 | // | |
1701 | // If the diff attribute requires computing the value, and hence | |
1702 | // won't be available until apply, the value is replaced with the | |
1703 | // computeID. | |
1704 | func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { | |
1705 | result := s.DeepCopy() | |
1706 | if result == nil { | |
1707 | result = new(InstanceState) | |
1708 | } | |
1709 | result.init() | |
1710 | ||
1711 | if s != nil { | |
1712 | s.Lock() | |
1713 | defer s.Unlock() | |
1714 | for k, v := range s.Attributes { | |
1715 | result.Attributes[k] = v | |
1716 | } | |
1717 | } | |
1718 | if d != nil { | |
1719 | for k, diff := range d.CopyAttributes() { | |
1720 | if diff.NewRemoved { | |
1721 | delete(result.Attributes, k) | |
1722 | continue | |
1723 | } | |
1724 | if diff.NewComputed { | |
1725 | result.Attributes[k] = config.UnknownVariableValue | |
1726 | continue | |
1727 | } | |
1728 | ||
1729 | result.Attributes[k] = diff.New | |
1730 | } | |
1731 | } | |
1732 | ||
1733 | return result | |
1734 | } | |
1735 | ||
1736 | func (s *InstanceState) String() string { | |
1737 | s.Lock() | |
1738 | defer s.Unlock() | |
1739 | ||
1740 | var buf bytes.Buffer | |
1741 | ||
1742 | if s == nil || s.ID == "" { | |
1743 | return "<not created>" | |
1744 | } | |
1745 | ||
1746 | buf.WriteString(fmt.Sprintf("ID = %s\n", s.ID)) | |
1747 | ||
1748 | attributes := s.Attributes | |
1749 | attrKeys := make([]string, 0, len(attributes)) | |
1750 | for ak, _ := range attributes { | |
1751 | if ak == "id" { | |
1752 | continue | |
1753 | } | |
1754 | ||
1755 | attrKeys = append(attrKeys, ak) | |
1756 | } | |
1757 | sort.Strings(attrKeys) | |
1758 | ||
1759 | for _, ak := range attrKeys { | |
1760 | av := attributes[ak] | |
1761 | buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av)) | |
1762 | } | |
1763 | ||
1764 | buf.WriteString(fmt.Sprintf("Tainted = %t\n", s.Tainted)) | |
1765 | ||
1766 | return buf.String() | |
1767 | } | |
1768 | ||
1769 | // EphemeralState is used for transient state that is only kept in-memory | |
1770 | type EphemeralState struct { | |
1771 | // ConnInfo is used for the providers to export information which is | |
1772 | // used to connect to the resource for provisioning. For example, | |
1773 | // this could contain SSH or WinRM credentials. | |
1774 | ConnInfo map[string]string `json:"-"` | |
1775 | ||
1776 | // Type is used to specify the resource type for this instance. This is only | |
1777 | // required for import operations (as documented). If the documentation | |
1778 | // doesn't state that you need to set this, then don't worry about | |
1779 | // setting it. | |
1780 | Type string `json:"-"` | |
1781 | } | |
1782 | ||
1783 | func (e *EphemeralState) init() { | |
1784 | if e.ConnInfo == nil { | |
1785 | e.ConnInfo = make(map[string]string) | |
1786 | } | |
1787 | } | |
1788 | ||
1789 | func (e *EphemeralState) DeepCopy() *EphemeralState { | |
1790 | copy, err := copystructure.Config{Lock: true}.Copy(e) | |
1791 | if err != nil { | |
1792 | panic(err) | |
1793 | } | |
1794 | ||
1795 | return copy.(*EphemeralState) | |
1796 | } | |
1797 | ||
1798 | type jsonStateVersionIdentifier struct { | |
1799 | Version int `json:"version"` | |
1800 | } | |
1801 | ||
1802 | // Check if this is a V0 format - the magic bytes at the start of the file | |
1803 | // should be "tfstate" if so. We no longer support upgrading this type of | |
1804 | // state but return an error message explaining to a user how they can | |
1805 | // upgrade via the 0.6.x series. | |
1806 | func testForV0State(buf *bufio.Reader) error { | |
1807 | start, err := buf.Peek(len("tfstate")) | |
1808 | if err != nil { | |
1809 | return fmt.Errorf("Failed to check for magic bytes: %v", err) | |
1810 | } | |
1811 | if string(start) == "tfstate" { | |
1812 | return fmt.Errorf("Terraform 0.7 no longer supports upgrading the binary state\n" + | |
1813 | "format which was used prior to Terraform 0.3. Please upgrade\n" + | |
1814 | "this state file using Terraform 0.6.16 prior to using it with\n" + | |
1815 | "Terraform 0.7.") | |
1816 | } | |
1817 | ||
1818 | return nil | |
1819 | } | |
1820 | ||
1821 | // ErrNoState is returned by ReadState when the io.Reader contains no data | |
1822 | var ErrNoState = errors.New("no state") | |
1823 | ||
1824 | // ReadState reads a state structure out of a reader in the format that | |
1825 | // was written by WriteState. | |
1826 | func ReadState(src io.Reader) (*State, error) { | |
1827 | buf := bufio.NewReader(src) | |
1828 | if _, err := buf.Peek(1); err != nil { | |
1829 | // the error is either io.EOF or "invalid argument", and both are from | |
1830 | // an empty state. | |
1831 | return nil, ErrNoState | |
1832 | } | |
1833 | ||
1834 | if err := testForV0State(buf); err != nil { | |
1835 | return nil, err | |
1836 | } | |
1837 | ||
1838 | // If we are JSON we buffer the whole thing in memory so we can read it twice. | |
1839 | // This is suboptimal, but will work for now. | |
1840 | jsonBytes, err := ioutil.ReadAll(buf) | |
1841 | if err != nil { | |
1842 | return nil, fmt.Errorf("Reading state file failed: %v", err) | |
1843 | } | |
1844 | ||
1845 | versionIdentifier := &jsonStateVersionIdentifier{} | |
1846 | if err := json.Unmarshal(jsonBytes, versionIdentifier); err != nil { | |
1847 | return nil, fmt.Errorf("Decoding state file version failed: %v", err) | |
1848 | } | |
1849 | ||
1850 | var result *State | |
1851 | switch versionIdentifier.Version { | |
1852 | case 0: | |
1853 | return nil, fmt.Errorf("State version 0 is not supported as JSON.") | |
1854 | case 1: | |
1855 | v1State, err := ReadStateV1(jsonBytes) | |
1856 | if err != nil { | |
1857 | return nil, err | |
1858 | } | |
1859 | ||
1860 | v2State, err := upgradeStateV1ToV2(v1State) | |
1861 | if err != nil { | |
1862 | return nil, err | |
1863 | } | |
1864 | ||
1865 | v3State, err := upgradeStateV2ToV3(v2State) | |
1866 | if err != nil { | |
1867 | return nil, err | |
1868 | } | |
1869 | ||
1870 | // increment the Serial whenever we upgrade state | |
1871 | v3State.Serial++ | |
1872 | result = v3State | |
1873 | case 2: | |
1874 | v2State, err := ReadStateV2(jsonBytes) | |
1875 | if err != nil { | |
1876 | return nil, err | |
1877 | } | |
1878 | v3State, err := upgradeStateV2ToV3(v2State) | |
1879 | if err != nil { | |
1880 | return nil, err | |
1881 | } | |
1882 | ||
1883 | v3State.Serial++ | |
1884 | result = v3State | |
1885 | case 3: | |
1886 | v3State, err := ReadStateV3(jsonBytes) | |
1887 | if err != nil { | |
1888 | return nil, err | |
1889 | } | |
1890 | ||
1891 | result = v3State | |
1892 | default: | |
1893 | return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", | |
1894 | SemVersion.String(), versionIdentifier.Version) | |
1895 | } | |
1896 | ||
1897 | // If we reached this place we must have a result set | |
1898 | if result == nil { | |
1899 | panic("resulting state in load not set, assertion failed") | |
1900 | } | |
1901 | ||
1902 | // Prune the state when read it. Its possible to write unpruned states or | |
1903 | // for a user to make a state unpruned (nil-ing a module state for example). | |
1904 | result.prune() | |
1905 | ||
1906 | // Validate the state file is valid | |
1907 | if err := result.Validate(); err != nil { | |
1908 | return nil, err | |
1909 | } | |
1910 | ||
1911 | return result, nil | |
1912 | } | |
1913 | ||
1914 | func ReadStateV1(jsonBytes []byte) (*stateV1, error) { | |
1915 | v1State := &stateV1{} | |
1916 | if err := json.Unmarshal(jsonBytes, v1State); err != nil { | |
1917 | return nil, fmt.Errorf("Decoding state file failed: %v", err) | |
1918 | } | |
1919 | ||
1920 | if v1State.Version != 1 { | |
1921 | return nil, fmt.Errorf("Decoded state version did not match the decoder selection: "+ | |
1922 | "read %d, expected 1", v1State.Version) | |
1923 | } | |
1924 | ||
1925 | return v1State, nil | |
1926 | } | |
1927 | ||
1928 | func ReadStateV2(jsonBytes []byte) (*State, error) { | |
1929 | state := &State{} | |
1930 | if err := json.Unmarshal(jsonBytes, state); err != nil { | |
1931 | return nil, fmt.Errorf("Decoding state file failed: %v", err) | |
1932 | } | |
1933 | ||
1934 | // Check the version, this to ensure we don't read a future | |
1935 | // version that we don't understand | |
1936 | if state.Version > StateVersion { | |
1937 | return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", | |
1938 | SemVersion.String(), state.Version) | |
1939 | } | |
1940 | ||
1941 | // Make sure the version is semantic | |
1942 | if state.TFVersion != "" { | |
1943 | if _, err := version.NewVersion(state.TFVersion); err != nil { | |
1944 | return nil, fmt.Errorf( | |
1945 | "State contains invalid version: %s\n\n"+ | |
1946 | "Terraform validates the version format prior to writing it. This\n"+ | |
1947 | "means that this is invalid of the state becoming corrupted through\n"+ | |
1948 | "some external means. Please manually modify the Terraform version\n"+ | |
1949 | "field to be a proper semantic version.", | |
1950 | state.TFVersion) | |
1951 | } | |
1952 | } | |
1953 | ||
1954 | // catch any unitialized fields in the state | |
1955 | state.init() | |
1956 | ||
1957 | // Sort it | |
1958 | state.sort() | |
1959 | ||
1960 | return state, nil | |
1961 | } | |
1962 | ||
1963 | func ReadStateV3(jsonBytes []byte) (*State, error) { | |
1964 | state := &State{} | |
1965 | if err := json.Unmarshal(jsonBytes, state); err != nil { | |
1966 | return nil, fmt.Errorf("Decoding state file failed: %v", err) | |
1967 | } | |
1968 | ||
1969 | // Check the version, this to ensure we don't read a future | |
1970 | // version that we don't understand | |
1971 | if state.Version > StateVersion { | |
1972 | return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", | |
1973 | SemVersion.String(), state.Version) | |
1974 | } | |
1975 | ||
1976 | // Make sure the version is semantic | |
1977 | if state.TFVersion != "" { | |
1978 | if _, err := version.NewVersion(state.TFVersion); err != nil { | |
1979 | return nil, fmt.Errorf( | |
1980 | "State contains invalid version: %s\n\n"+ | |
1981 | "Terraform validates the version format prior to writing it. This\n"+ | |
1982 | "means that this is invalid of the state becoming corrupted through\n"+ | |
1983 | "some external means. Please manually modify the Terraform version\n"+ | |
1984 | "field to be a proper semantic version.", | |
1985 | state.TFVersion) | |
1986 | } | |
1987 | } | |
1988 | ||
1989 | // catch any unitialized fields in the state | |
1990 | state.init() | |
1991 | ||
1992 | // Sort it | |
1993 | state.sort() | |
1994 | ||
1995 | // Now we write the state back out to detect any changes in normaliztion. | |
1996 | // If our state is now written out differently, bump the serial number to | |
1997 | // prevent conflicts. | |
1998 | var buf bytes.Buffer | |
1999 | err := WriteState(state, &buf) | |
2000 | if err != nil { | |
2001 | return nil, err | |
2002 | } | |
2003 | ||
2004 | if !bytes.Equal(jsonBytes, buf.Bytes()) { | |
2005 | log.Println("[INFO] state modified during read or write. incrementing serial number") | |
2006 | state.Serial++ | |
2007 | } | |
2008 | ||
2009 | return state, nil | |
2010 | } | |
2011 | ||
2012 | // WriteState writes a state somewhere in a binary format. | |
2013 | func WriteState(d *State, dst io.Writer) error { | |
2014 | // writing a nil state is a noop. | |
2015 | if d == nil { | |
2016 | return nil | |
2017 | } | |
2018 | ||
2019 | // make sure we have no uninitialized fields | |
2020 | d.init() | |
2021 | ||
2022 | // Make sure it is sorted | |
2023 | d.sort() | |
2024 | ||
2025 | // Ensure the version is set | |
2026 | d.Version = StateVersion | |
2027 | ||
2028 | // If the TFVersion is set, verify it. We used to just set the version | |
2029 | // here, but this isn't safe since it changes the MD5 sum on some remote | |
2030 | // state storage backends such as Atlas. We now leave it be if needed. | |
2031 | if d.TFVersion != "" { | |
2032 | if _, err := version.NewVersion(d.TFVersion); err != nil { | |
2033 | return fmt.Errorf( | |
2034 | "Error writing state, invalid version: %s\n\n"+ | |
2035 | "The Terraform version when writing the state must be a semantic\n"+ | |
2036 | "version.", | |
2037 | d.TFVersion) | |
2038 | } | |
2039 | } | |
2040 | ||
2041 | // Encode the data in a human-friendly way | |
2042 | data, err := json.MarshalIndent(d, "", " ") | |
2043 | if err != nil { | |
2044 | return fmt.Errorf("Failed to encode state: %s", err) | |
2045 | } | |
2046 | ||
2047 | // We append a newline to the data because MarshalIndent doesn't | |
2048 | data = append(data, '\n') | |
2049 | ||
2050 | // Write the data out to the dst | |
2051 | if _, err := io.Copy(dst, bytes.NewReader(data)); err != nil { | |
2052 | return fmt.Errorf("Failed to write state: %v", err) | |
2053 | } | |
2054 | ||
2055 | return nil | |
2056 | } | |
2057 | ||
2058 | // resourceNameSort implements the sort.Interface to sort name parts lexically for | |
2059 | // strings and numerically for integer indexes. | |
2060 | type resourceNameSort []string | |
2061 | ||
2062 | func (r resourceNameSort) Len() int { return len(r) } | |
2063 | func (r resourceNameSort) Swap(i, j int) { r[i], r[j] = r[j], r[i] } | |
2064 | ||
2065 | func (r resourceNameSort) Less(i, j int) bool { | |
2066 | iParts := strings.Split(r[i], ".") | |
2067 | jParts := strings.Split(r[j], ".") | |
2068 | ||
2069 | end := len(iParts) | |
2070 | if len(jParts) < end { | |
2071 | end = len(jParts) | |
2072 | } | |
2073 | ||
2074 | for idx := 0; idx < end; idx++ { | |
2075 | if iParts[idx] == jParts[idx] { | |
2076 | continue | |
2077 | } | |
2078 | ||
2079 | // sort on the first non-matching part | |
2080 | iInt, iIntErr := strconv.Atoi(iParts[idx]) | |
2081 | jInt, jIntErr := strconv.Atoi(jParts[idx]) | |
2082 | ||
2083 | switch { | |
2084 | case iIntErr == nil && jIntErr == nil: | |
2085 | // sort numerically if both parts are integers | |
2086 | return iInt < jInt | |
2087 | case iIntErr == nil: | |
2088 | // numbers sort before strings | |
2089 | return true | |
2090 | case jIntErr == nil: | |
2091 | return false | |
2092 | default: | |
2093 | return iParts[idx] < jParts[idx] | |
2094 | } | |
2095 | } | |
2096 | ||
2097 | return r[i] < r[j] | |
2098 | } | |
2099 | ||
2100 | // moduleStateSort implements sort.Interface to sort module states | |
2101 | type moduleStateSort []*ModuleState | |
2102 | ||
2103 | func (s moduleStateSort) Len() int { | |
2104 | return len(s) | |
2105 | } | |
2106 | ||
2107 | func (s moduleStateSort) Less(i, j int) bool { | |
2108 | a := s[i] | |
2109 | b := s[j] | |
2110 | ||
2111 | // If either is nil, then the nil one is "less" than | |
2112 | if a == nil || b == nil { | |
2113 | return a == nil | |
2114 | } | |
2115 | ||
2116 | // If the lengths are different, then the shorter one always wins | |
2117 | if len(a.Path) != len(b.Path) { | |
2118 | return len(a.Path) < len(b.Path) | |
2119 | } | |
2120 | ||
2121 | // Otherwise, compare lexically | |
2122 | return strings.Join(a.Path, ".") < strings.Join(b.Path, ".") | |
2123 | } | |
2124 | ||
2125 | func (s moduleStateSort) Swap(i, j int) { | |
2126 | s[i], s[j] = s[j], s[i] | |
2127 | } | |
2128 | ||
2129 | const stateValidateErrMultiModule = ` | |
2130 | Multiple modules with the same path: %s | |
2131 | ||
2132 | This means that there are multiple entries in the "modules" field | |
2133 | in your state file that point to the same module. This will cause Terraform | |
2134 | to behave in unexpected and error prone ways and is invalid. Please back up | |
2135 | and modify your state file manually to resolve this. | |
2136 | ` |