github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/terraform/state.go (about) 1 package terraform 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "io" 9 "log" 10 "reflect" 11 "sort" 12 "strings" 13 14 "github.com/hashicorp/terraform/config" 15 ) 16 17 const ( 18 // StateVersion is the current version for our state file 19 StateVersion = 1 20 ) 21 22 // rootModulePath is the path of the root module 23 var rootModulePath = []string{"root"} 24 25 // State keeps track of a snapshot state-of-the-world that Terraform 26 // can use to keep track of what real world resources it is actually 27 // managing. This is the latest format as of Terraform 0.3 28 type State struct { 29 // Version is the protocol version. Currently only "1". 30 Version int `json:"version"` 31 32 // Serial is incremented on any operation that modifies 33 // the State file. It is used to detect potentially conflicting 34 // updates. 35 Serial int64 `json:"serial"` 36 37 // Remote is used to track the metadata required to 38 // pull and push state files from a remote storage endpoint. 39 Remote *RemoteState `json:"remote,omitempty"` 40 41 // Modules contains all the modules in a breadth-first order 42 Modules []*ModuleState `json:"modules"` 43 } 44 45 // NewState is used to initialize a blank state 46 func NewState() *State { 47 s := &State{} 48 s.init() 49 return s 50 } 51 52 // Children returns the ModuleStates that are direct children of 53 // the given path. If the path is "root", for example, then children 54 // returned might be "root.child", but not "root.child.grandchild". 55 func (s *State) Children(path []string) []*ModuleState { 56 // TODO: test 57 58 result := make([]*ModuleState, 0) 59 for _, m := range s.Modules { 60 if len(m.Path) != len(path)+1 { 61 continue 62 } 63 if !reflect.DeepEqual(path, m.Path[:len(path)]) { 64 continue 65 } 66 67 result = append(result, m) 68 } 69 70 return result 71 } 72 73 // AddModule adds the module with the given path to the state. 74 // 75 // This should be the preferred method to add module states since it 76 // allows us to optimize lookups later as well as control sorting. 77 func (s *State) AddModule(path []string) *ModuleState { 78 m := &ModuleState{Path: path} 79 m.init() 80 s.Modules = append(s.Modules, m) 81 s.sort() 82 return m 83 } 84 85 // ModuleByPath is used to lookup the module state for the given path. 86 // This should be the prefered lookup mechanism as it allows for future 87 // lookup optimizations. 88 func (s *State) ModuleByPath(path []string) *ModuleState { 89 if s == nil { 90 return nil 91 } 92 for _, mod := range s.Modules { 93 if mod.Path == nil { 94 panic("missing module path") 95 } 96 if reflect.DeepEqual(mod.Path, path) { 97 return mod 98 } 99 } 100 return nil 101 } 102 103 // ModuleOrphans returns all the module orphans in this state by 104 // returning their full paths. These paths can be used with ModuleByPath 105 // to return the actual state. 106 func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { 107 childrenKeys := make(map[string]struct{}) 108 if c != nil { 109 for _, m := range c.Modules { 110 childrenKeys[m.Name] = struct{}{} 111 } 112 } 113 114 // Go over the direct children and find any that aren't in our 115 // keys. 116 var orphans [][]string 117 for _, m := range s.Children(path) { 118 if _, ok := childrenKeys[m.Path[len(m.Path)-1]]; ok { 119 continue 120 } 121 122 orphans = append(orphans, m.Path) 123 } 124 125 return orphans 126 } 127 128 // Empty returns true if the state is empty. 129 func (s *State) Empty() bool { 130 if s == nil { 131 return true 132 } 133 134 return len(s.Modules) == 0 135 } 136 137 // IsRemote returns true if State represents a state that exists and is 138 // remote. 139 func (s *State) IsRemote() bool { 140 if s == nil { 141 return false 142 } 143 if s.Remote == nil { 144 return false 145 } 146 if s.Remote.Type == "" { 147 return false 148 } 149 150 return true 151 } 152 153 // RootModule returns the ModuleState for the root module 154 func (s *State) RootModule() *ModuleState { 155 root := s.ModuleByPath(rootModulePath) 156 if root == nil { 157 panic("missing root module") 158 } 159 return root 160 } 161 162 // Equal tests if one state is equal to another. 163 func (s *State) Equal(other *State) bool { 164 // If one is nil, we do a direct check 165 if s == nil || other == nil { 166 return s == other 167 } 168 169 // If the versions are different, they're certainly not equal 170 if s.Version != other.Version { 171 return false 172 } 173 174 // If any of the modules are not equal, then this state isn't equal 175 if len(s.Modules) != len(other.Modules) { 176 return false 177 } 178 for _, m := range s.Modules { 179 // This isn't very optimal currently but works. 180 otherM := other.ModuleByPath(m.Path) 181 if otherM == nil { 182 return false 183 } 184 185 // If they're not equal, then we're not equal! 186 if !m.Equal(otherM) { 187 return false 188 } 189 } 190 191 return true 192 } 193 194 // DeepCopy performs a deep copy of the state structure and returns 195 // a new structure. 196 func (s *State) DeepCopy() *State { 197 if s == nil { 198 return nil 199 } 200 n := &State{ 201 Version: s.Version, 202 Serial: s.Serial, 203 Modules: make([]*ModuleState, 0, len(s.Modules)), 204 } 205 for _, mod := range s.Modules { 206 n.Modules = append(n.Modules, mod.deepcopy()) 207 } 208 if s.Remote != nil { 209 n.Remote = s.Remote.deepcopy() 210 } 211 return n 212 } 213 214 // IncrementSerialMaybe increments the serial number of this state 215 // if it different from the other state. 216 func (s *State) IncrementSerialMaybe(other *State) { 217 if !s.Equal(other) { 218 s.Serial++ 219 } 220 } 221 222 func (s *State) init() { 223 if s.Version == 0 { 224 s.Version = StateVersion 225 } 226 if len(s.Modules) == 0 { 227 root := &ModuleState{ 228 Path: rootModulePath, 229 } 230 root.init() 231 s.Modules = []*ModuleState{root} 232 } 233 } 234 235 // prune is used to remove any resources that are no longer required 236 func (s *State) prune() { 237 if s == nil { 238 return 239 } 240 for _, mod := range s.Modules { 241 mod.prune() 242 } 243 if s.Remote != nil && s.Remote.Empty() { 244 s.Remote = nil 245 } 246 } 247 248 // sort sorts the modules 249 func (s *State) sort() { 250 sort.Sort(moduleStateSort(s.Modules)) 251 252 // Allow modules to be sorted 253 for _, m := range s.Modules { 254 m.sort() 255 } 256 } 257 258 func (s *State) GoString() string { 259 return fmt.Sprintf("*%#v", *s) 260 } 261 262 func (s *State) String() string { 263 var buf bytes.Buffer 264 for _, m := range s.Modules { 265 mStr := m.String() 266 267 // If we're the root module, we just write the output directly. 268 if reflect.DeepEqual(m.Path, rootModulePath) { 269 buf.WriteString(mStr + "\n") 270 continue 271 } 272 273 buf.WriteString(fmt.Sprintf("module.%s:\n", strings.Join(m.Path[1:], "."))) 274 275 s := bufio.NewScanner(strings.NewReader(mStr)) 276 for s.Scan() { 277 text := s.Text() 278 if text != "" { 279 text = " " + text 280 } 281 282 buf.WriteString(fmt.Sprintf("%s\n", text)) 283 } 284 } 285 286 return strings.TrimSpace(buf.String()) 287 } 288 289 // RemoteState is used to track the information about a remote 290 // state store that we push/pull state to. 291 type RemoteState struct { 292 // Type controls the client we use for the remote state 293 Type string `json:"type"` 294 295 // Config is used to store arbitrary configuration that 296 // is type specific 297 Config map[string]string `json:"config"` 298 } 299 300 func (r *RemoteState) deepcopy() *RemoteState { 301 confCopy := make(map[string]string, len(r.Config)) 302 for k, v := range r.Config { 303 confCopy[k] = v 304 } 305 return &RemoteState{ 306 Type: r.Type, 307 Config: confCopy, 308 } 309 } 310 311 func (r *RemoteState) Empty() bool { 312 return r == nil || r.Type == "" 313 } 314 315 func (r *RemoteState) Equals(other *RemoteState) bool { 316 if r.Type != other.Type { 317 return false 318 } 319 if len(r.Config) != len(other.Config) { 320 return false 321 } 322 for k, v := range r.Config { 323 if other.Config[k] != v { 324 return false 325 } 326 } 327 return true 328 } 329 330 // ModuleState is used to track all the state relevant to a single 331 // module. Previous to Terraform 0.3, all state belonged to the "root" 332 // module. 333 type ModuleState struct { 334 // Path is the import path from the root module. Modules imports are 335 // always disjoint, so the path represents amodule tree 336 Path []string `json:"path"` 337 338 // Outputs declared by the module and maintained for each module 339 // even though only the root module technically needs to be kept. 340 // This allows operators to inspect values at the boundaries. 341 Outputs map[string]string `json:"outputs"` 342 343 // Resources is a mapping of the logically named resource to 344 // the state of the resource. Each resource may actually have 345 // N instances underneath, although a user only needs to think 346 // about the 1:1 case. 347 Resources map[string]*ResourceState `json:"resources"` 348 349 // Dependencies are a list of things that this module relies on 350 // existing to remain intact. For example: an module may depend 351 // on a VPC ID given by an aws_vpc resource. 352 // 353 // Terraform uses this information to build valid destruction 354 // orders and to warn the user if they're destroying a module that 355 // another resource depends on. 356 // 357 // Things can be put into this list that may not be managed by 358 // Terraform. If Terraform doesn't find a matching ID in the 359 // overall state, then it assumes it isn't managed and doesn't 360 // worry about it. 361 Dependencies []string `json:"depends_on,omitempty"` 362 } 363 364 // Equal tests whether one module state is equal to another. 365 func (m *ModuleState) Equal(other *ModuleState) bool { 366 // Paths must be equal 367 if !reflect.DeepEqual(m.Path, other.Path) { 368 return false 369 } 370 371 // Outputs must be equal 372 if len(m.Outputs) != len(other.Outputs) { 373 return false 374 } 375 for k, v := range m.Outputs { 376 if other.Outputs[k] != v { 377 return false 378 } 379 } 380 381 // Dependencies must be equal. This sorts these in place but 382 // this shouldn't cause any problems. 383 sort.Strings(m.Dependencies) 384 sort.Strings(other.Dependencies) 385 if len(m.Dependencies) != len(other.Dependencies) { 386 return false 387 } 388 for i, d := range m.Dependencies { 389 if other.Dependencies[i] != d { 390 return false 391 } 392 } 393 394 // Resources must be equal 395 if len(m.Resources) != len(other.Resources) { 396 return false 397 } 398 for k, r := range m.Resources { 399 otherR, ok := other.Resources[k] 400 if !ok { 401 return false 402 } 403 404 if !r.Equal(otherR) { 405 return false 406 } 407 } 408 409 return true 410 } 411 412 // IsRoot says whether or not this module diff is for the root module. 413 func (m *ModuleState) IsRoot() bool { 414 return reflect.DeepEqual(m.Path, rootModulePath) 415 } 416 417 // Orphans returns a list of keys of resources that are in the State 418 // but aren't present in the configuration itself. Hence, these keys 419 // represent the state of resources that are orphans. 420 func (m *ModuleState) Orphans(c *config.Config) []string { 421 keys := make(map[string]struct{}) 422 for k, _ := range m.Resources { 423 keys[k] = struct{}{} 424 } 425 426 if c != nil { 427 for _, r := range c.Resources { 428 delete(keys, r.Id()) 429 430 for k, _ := range keys { 431 if strings.HasPrefix(k, r.Id()+".") { 432 delete(keys, k) 433 } 434 } 435 } 436 } 437 438 result := make([]string, 0, len(keys)) 439 for k, _ := range keys { 440 result = append(result, k) 441 } 442 443 return result 444 } 445 446 // View returns a view with the given resource prefix. 447 func (m *ModuleState) View(id string) *ModuleState { 448 if m == nil { 449 return m 450 } 451 452 r := m.deepcopy() 453 for k, _ := range r.Resources { 454 if id == k || strings.HasPrefix(k, id+".") { 455 continue 456 } 457 458 delete(r.Resources, k) 459 } 460 461 return r 462 } 463 464 func (m *ModuleState) init() { 465 if m.Outputs == nil { 466 m.Outputs = make(map[string]string) 467 } 468 if m.Resources == nil { 469 m.Resources = make(map[string]*ResourceState) 470 } 471 } 472 473 func (m *ModuleState) deepcopy() *ModuleState { 474 if m == nil { 475 return nil 476 } 477 n := &ModuleState{ 478 Path: make([]string, len(m.Path)), 479 Outputs: make(map[string]string, len(m.Outputs)), 480 Resources: make(map[string]*ResourceState, len(m.Resources)), 481 } 482 copy(n.Path, m.Path) 483 for k, v := range m.Outputs { 484 n.Outputs[k] = v 485 } 486 for k, v := range m.Resources { 487 n.Resources[k] = v.deepcopy() 488 } 489 return n 490 } 491 492 // prune is used to remove any resources that are no longer required 493 func (m *ModuleState) prune() { 494 for k, v := range m.Resources { 495 v.prune() 496 497 if (v.Primary == nil || v.Primary.ID == "") && len(v.Tainted) == 0 { 498 delete(m.Resources, k) 499 } 500 } 501 502 for k, v := range m.Outputs { 503 if v == config.UnknownVariableValue { 504 delete(m.Outputs, k) 505 } 506 } 507 } 508 509 func (m *ModuleState) sort() { 510 for _, v := range m.Resources { 511 v.sort() 512 } 513 } 514 515 func (m *ModuleState) GoString() string { 516 return fmt.Sprintf("*%#v", *m) 517 } 518 519 func (m *ModuleState) String() string { 520 var buf bytes.Buffer 521 522 if len(m.Resources) == 0 { 523 buf.WriteString("<no state>") 524 } 525 526 names := make([]string, 0, len(m.Resources)) 527 for name, _ := range m.Resources { 528 names = append(names, name) 529 } 530 sort.Strings(names) 531 532 for _, k := range names { 533 rs := m.Resources[k] 534 var id string 535 if rs.Primary != nil { 536 id = rs.Primary.ID 537 } 538 if id == "" { 539 id = "<not created>" 540 } 541 542 taintStr := "" 543 if len(rs.Tainted) > 0 { 544 taintStr = fmt.Sprintf(" (%d tainted)", len(rs.Tainted)) 545 } 546 547 buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) 548 buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) 549 550 var attributes map[string]string 551 if rs.Primary != nil { 552 attributes = rs.Primary.Attributes 553 } 554 attrKeys := make([]string, 0, len(attributes)) 555 for ak, _ := range attributes { 556 if ak == "id" { 557 continue 558 } 559 560 attrKeys = append(attrKeys, ak) 561 } 562 sort.Strings(attrKeys) 563 564 for _, ak := range attrKeys { 565 av := attributes[ak] 566 buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) 567 } 568 569 for idx, t := range rs.Tainted { 570 buf.WriteString(fmt.Sprintf(" Tainted ID %d = %s\n", idx+1, t.ID)) 571 } 572 573 if len(rs.Dependencies) > 0 { 574 buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) 575 for _, dep := range rs.Dependencies { 576 buf.WriteString(fmt.Sprintf(" %s\n", dep)) 577 } 578 } 579 } 580 581 if len(m.Outputs) > 0 { 582 buf.WriteString("\nOutputs:\n\n") 583 584 ks := make([]string, 0, len(m.Outputs)) 585 for k, _ := range m.Outputs { 586 ks = append(ks, k) 587 } 588 sort.Strings(ks) 589 590 for _, k := range ks { 591 v := m.Outputs[k] 592 buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) 593 } 594 } 595 596 return buf.String() 597 } 598 599 // ResourceState holds the state of a resource that is used so that 600 // a provider can find and manage an existing resource as well as for 601 // storing attributes that are used to populate variables of child 602 // resources. 603 // 604 // Attributes has attributes about the created resource that are 605 // queryable in interpolation: "${type.id.attr}" 606 // 607 // Extra is just extra data that a provider can return that we store 608 // for later, but is not exposed in any way to the user. 609 // 610 type ResourceState struct { 611 // This is filled in and managed by Terraform, and is the resource 612 // type itself such as "mycloud_instance". If a resource provider sets 613 // this value, it won't be persisted. 614 Type string `json:"type"` 615 616 // Dependencies are a list of things that this resource relies on 617 // existing to remain intact. For example: an AWS instance might 618 // depend on a subnet (which itself might depend on a VPC, and so 619 // on). 620 // 621 // Terraform uses this information to build valid destruction 622 // orders and to warn the user if they're destroying a resource that 623 // another resource depends on. 624 // 625 // Things can be put into this list that may not be managed by 626 // Terraform. If Terraform doesn't find a matching ID in the 627 // overall state, then it assumes it isn't managed and doesn't 628 // worry about it. 629 Dependencies []string `json:"depends_on,omitempty"` 630 631 // Primary is the current active instance for this resource. 632 // It can be replaced but only after a successful creation. 633 // This is the instances on which providers will act. 634 Primary *InstanceState `json:"primary"` 635 636 // Tainted is used to track any underlying instances that 637 // have been created but are in a bad or unknown state and 638 // need to be cleaned up subsequently. In the 639 // standard case, there is only at most a single instance. 640 // However, in pathological cases, it is possible for the number 641 // of instances to accumulate. 642 Tainted []*InstanceState `json:"tainted,omitempty"` 643 } 644 645 // Equal tests whether two ResourceStates are equal. 646 func (s *ResourceState) Equal(other *ResourceState) bool { 647 if s.Type != other.Type { 648 return false 649 } 650 651 // Dependencies must be equal 652 sort.Strings(s.Dependencies) 653 sort.Strings(other.Dependencies) 654 if len(s.Dependencies) != len(other.Dependencies) { 655 return false 656 } 657 for i, d := range s.Dependencies { 658 if other.Dependencies[i] != d { 659 return false 660 } 661 } 662 663 // States must be equal 664 if !s.Primary.Equal(other.Primary) { 665 return false 666 } 667 668 // Tainted 669 taints := make(map[string]*InstanceState) 670 for _, t := range other.Tainted { 671 if t == nil { 672 continue 673 } 674 675 taints[t.ID] = t 676 } 677 for _, t := range s.Tainted { 678 if t == nil { 679 continue 680 } 681 682 otherT, ok := taints[t.ID] 683 if !ok { 684 return false 685 } 686 delete(taints, t.ID) 687 688 if !t.Equal(otherT) { 689 return false 690 } 691 } 692 693 // This means that we have stuff in other tainted that we don't 694 // have, so it is not equal. 695 if len(taints) > 0 { 696 return false 697 } 698 699 return true 700 } 701 702 func (r *ResourceState) init() { 703 if r.Primary == nil { 704 r.Primary = &InstanceState{} 705 } 706 r.Primary.init() 707 } 708 709 func (r *ResourceState) deepcopy() *ResourceState { 710 if r == nil { 711 return nil 712 } 713 n := &ResourceState{ 714 Type: r.Type, 715 Dependencies: make([]string, len(r.Dependencies)), 716 Primary: r.Primary.deepcopy(), 717 Tainted: make([]*InstanceState, 0, len(r.Tainted)), 718 } 719 copy(n.Dependencies, r.Dependencies) 720 for _, inst := range r.Tainted { 721 n.Tainted = append(n.Tainted, inst.deepcopy()) 722 } 723 return n 724 } 725 726 // prune is used to remove any instances that are no longer required 727 func (r *ResourceState) prune() { 728 n := len(r.Tainted) 729 for i := 0; i < n; i++ { 730 inst := r.Tainted[i] 731 if inst == nil || inst.ID == "" { 732 copy(r.Tainted[i:], r.Tainted[i+1:]) 733 r.Tainted[n-1] = nil 734 n-- 735 i-- 736 } 737 } 738 739 r.Tainted = r.Tainted[:n] 740 } 741 742 func (r *ResourceState) sort() { 743 sort.Strings(r.Dependencies) 744 } 745 746 func (s *ResourceState) GoString() string { 747 return fmt.Sprintf("*%#v", *s) 748 } 749 750 func (s *ResourceState) String() string { 751 var buf bytes.Buffer 752 buf.WriteString(fmt.Sprintf("Type = %s", s.Type)) 753 return buf.String() 754 } 755 756 // InstanceState is used to track the unique state information belonging 757 // to a given instance. 758 type InstanceState struct { 759 // A unique ID for this resource. This is opaque to Terraform 760 // and is only meant as a lookup mechanism for the providers. 761 ID string `json:"id"` 762 763 // Attributes are basic information about the resource. Any keys here 764 // are accessible in variable format within Terraform configurations: 765 // ${resourcetype.name.attribute}. 766 Attributes map[string]string `json:"attributes,omitempty"` 767 768 // Ephemeral is used to store any state associated with this instance 769 // that is necessary for the Terraform run to complete, but is not 770 // persisted to a state file. 771 Ephemeral EphemeralState `json:"-"` 772 } 773 774 func (i *InstanceState) init() { 775 if i.Attributes == nil { 776 i.Attributes = make(map[string]string) 777 } 778 i.Ephemeral.init() 779 } 780 781 func (i *InstanceState) deepcopy() *InstanceState { 782 if i == nil { 783 return nil 784 } 785 n := &InstanceState{ 786 ID: i.ID, 787 Ephemeral: *i.Ephemeral.deepcopy(), 788 } 789 if i.Attributes != nil { 790 n.Attributes = make(map[string]string, len(i.Attributes)) 791 for k, v := range i.Attributes { 792 n.Attributes[k] = v 793 } 794 } 795 return n 796 } 797 798 func (s *InstanceState) Equal(other *InstanceState) bool { 799 // Short circuit some nil checks 800 if s == nil || other == nil { 801 return s == other 802 } 803 804 // IDs must be equal 805 if s.ID != other.ID { 806 return false 807 } 808 809 // Attributes must be equal 810 if len(s.Attributes) != len(other.Attributes) { 811 return false 812 } 813 for k, v := range s.Attributes { 814 otherV, ok := other.Attributes[k] 815 if !ok { 816 return false 817 } 818 819 if v != otherV { 820 return false 821 } 822 } 823 824 return true 825 } 826 827 // MergeDiff takes a ResourceDiff and merges the attributes into 828 // this resource state in order to generate a new state. This new 829 // state can be used to provide updated attribute lookups for 830 // variable interpolation. 831 // 832 // If the diff attribute requires computing the value, and hence 833 // won't be available until apply, the value is replaced with the 834 // computeID. 835 func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { 836 result := s.deepcopy() 837 if result == nil { 838 result = new(InstanceState) 839 } 840 result.init() 841 842 if s != nil { 843 for k, v := range s.Attributes { 844 result.Attributes[k] = v 845 } 846 } 847 if d != nil { 848 for k, diff := range d.Attributes { 849 if diff.NewRemoved { 850 delete(result.Attributes, k) 851 continue 852 } 853 if diff.NewComputed { 854 result.Attributes[k] = config.UnknownVariableValue 855 continue 856 } 857 858 result.Attributes[k] = diff.New 859 } 860 } 861 862 return result 863 } 864 865 func (i *InstanceState) GoString() string { 866 return fmt.Sprintf("*%#v", *i) 867 } 868 869 func (i *InstanceState) String() string { 870 var buf bytes.Buffer 871 872 if i == nil || i.ID == "" { 873 return "<not created>" 874 } 875 876 buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID)) 877 878 attributes := i.Attributes 879 attrKeys := make([]string, 0, len(attributes)) 880 for ak, _ := range attributes { 881 if ak == "id" { 882 continue 883 } 884 885 attrKeys = append(attrKeys, ak) 886 } 887 sort.Strings(attrKeys) 888 889 for _, ak := range attrKeys { 890 av := attributes[ak] 891 buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av)) 892 } 893 894 return buf.String() 895 } 896 897 // EphemeralState is used for transient state that is only kept in-memory 898 type EphemeralState struct { 899 // ConnInfo is used for the providers to export information which is 900 // used to connect to the resource for provisioning. For example, 901 // this could contain SSH or WinRM credentials. 902 ConnInfo map[string]string `json:"-"` 903 } 904 905 func (e *EphemeralState) init() { 906 if e.ConnInfo == nil { 907 e.ConnInfo = make(map[string]string) 908 } 909 } 910 911 func (e *EphemeralState) deepcopy() *EphemeralState { 912 if e == nil { 913 return nil 914 } 915 n := &EphemeralState{} 916 if e.ConnInfo != nil { 917 n.ConnInfo = make(map[string]string, len(e.ConnInfo)) 918 for k, v := range e.ConnInfo { 919 n.ConnInfo[k] = v 920 } 921 } 922 return n 923 } 924 925 // ReadState reads a state structure out of a reader in the format that 926 // was written by WriteState. 927 func ReadState(src io.Reader) (*State, error) { 928 buf := bufio.NewReader(src) 929 930 // Check if this is a V1 format 931 start, err := buf.Peek(len(stateFormatMagic)) 932 if err != nil { 933 return nil, fmt.Errorf("Failed to check for magic bytes: %v", err) 934 } 935 if string(start) == stateFormatMagic { 936 // Read the old state 937 old, err := ReadStateV1(buf) 938 if err != nil { 939 return nil, err 940 } 941 return upgradeV1State(old) 942 } 943 944 // Otherwise, must be V2 945 dec := json.NewDecoder(buf) 946 state := &State{} 947 if err := dec.Decode(state); err != nil { 948 return nil, fmt.Errorf("Decoding state file failed: %v", err) 949 } 950 951 // Check the version, this to ensure we don't read a future 952 // version that we don't understand 953 if state.Version > StateVersion { 954 return nil, fmt.Errorf("State version %d not supported, please update.", 955 state.Version) 956 } 957 958 // Sort it 959 state.sort() 960 961 return state, nil 962 } 963 964 // WriteState writes a state somewhere in a binary format. 965 func WriteState(d *State, dst io.Writer) error { 966 // Make sure it is sorted 967 d.sort() 968 969 // Ensure the version is set 970 d.Version = StateVersion 971 972 // Encode the data in a human-friendly way 973 data, err := json.MarshalIndent(d, "", " ") 974 if err != nil { 975 return fmt.Errorf("Failed to encode state: %s", err) 976 } 977 978 // We append a newline to the data because MarshalIndent doesn't 979 data = append(data, '\n') 980 981 // Write the data out to the dst 982 if _, err := io.Copy(dst, bytes.NewReader(data)); err != nil { 983 return fmt.Errorf("Failed to write state: %v", err) 984 } 985 986 return nil 987 } 988 989 // upgradeV1State is used to upgrade a V1 state representation 990 // into a proper State representation. 991 func upgradeV1State(old *StateV1) (*State, error) { 992 s := &State{} 993 s.init() 994 995 // Old format had no modules, so we migrate everything 996 // directly into the root module. 997 root := s.RootModule() 998 999 // Copy the outputs 1000 root.Outputs = old.Outputs 1001 1002 // Upgrade the resources 1003 for id, rs := range old.Resources { 1004 newRs := &ResourceState{ 1005 Type: rs.Type, 1006 } 1007 root.Resources[id] = newRs 1008 1009 // Migrate to an instance state 1010 instance := &InstanceState{ 1011 ID: rs.ID, 1012 Attributes: rs.Attributes, 1013 } 1014 1015 // Check if this is the primary or tainted instance 1016 if _, ok := old.Tainted[id]; ok { 1017 newRs.Tainted = append(newRs.Tainted, instance) 1018 } else { 1019 newRs.Primary = instance 1020 } 1021 1022 // Warn if the resource uses Extra, as there is 1023 // no upgrade path for this! Now totally deprecated. 1024 if len(rs.Extra) > 0 { 1025 log.Printf( 1026 "[WARN] Resource %s uses deprecated attribute "+ 1027 "storage, state file upgrade may be incomplete.", 1028 rs.ID, 1029 ) 1030 } 1031 } 1032 return s, nil 1033 } 1034 1035 // moduleStateSort implements sort.Interface to sort module states 1036 type moduleStateSort []*ModuleState 1037 1038 func (s moduleStateSort) Len() int { 1039 return len(s) 1040 } 1041 1042 func (s moduleStateSort) Less(i, j int) bool { 1043 a := s[i] 1044 b := s[j] 1045 1046 // If the lengths are different, then the shorter one always wins 1047 if len(a.Path) != len(b.Path) { 1048 return len(a.Path) < len(b.Path) 1049 } 1050 1051 // Otherwise, compare by last path element 1052 idx := len(a.Path) - 1 1053 return a.Path[idx] < b.Path[idx] 1054 } 1055 1056 func (s moduleStateSort) Swap(i, j int) { 1057 s[i], s[j] = s[j], s[i] 1058 }