github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/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 == nil { 218 return 219 } 220 if other == nil { 221 return 222 } 223 if s.Serial > other.Serial { 224 return 225 } 226 if !s.Equal(other) { 227 if other.Serial > s.Serial { 228 s.Serial = other.Serial 229 } 230 231 s.Serial++ 232 } 233 } 234 235 func (s *State) init() { 236 if s.Version == 0 { 237 s.Version = StateVersion 238 } 239 if len(s.Modules) == 0 { 240 root := &ModuleState{ 241 Path: rootModulePath, 242 } 243 root.init() 244 s.Modules = []*ModuleState{root} 245 } 246 } 247 248 // prune is used to remove any resources that are no longer required 249 func (s *State) prune() { 250 if s == nil { 251 return 252 } 253 for _, mod := range s.Modules { 254 mod.prune() 255 } 256 if s.Remote != nil && s.Remote.Empty() { 257 s.Remote = nil 258 } 259 } 260 261 // sort sorts the modules 262 func (s *State) sort() { 263 sort.Sort(moduleStateSort(s.Modules)) 264 265 // Allow modules to be sorted 266 for _, m := range s.Modules { 267 m.sort() 268 } 269 } 270 271 func (s *State) GoString() string { 272 return fmt.Sprintf("*%#v", *s) 273 } 274 275 func (s *State) String() string { 276 if s == nil { 277 return "<nil>" 278 } 279 280 var buf bytes.Buffer 281 for _, m := range s.Modules { 282 mStr := m.String() 283 284 // If we're the root module, we just write the output directly. 285 if reflect.DeepEqual(m.Path, rootModulePath) { 286 buf.WriteString(mStr + "\n") 287 continue 288 } 289 290 buf.WriteString(fmt.Sprintf("module.%s:\n", strings.Join(m.Path[1:], "."))) 291 292 s := bufio.NewScanner(strings.NewReader(mStr)) 293 for s.Scan() { 294 text := s.Text() 295 if text != "" { 296 text = " " + text 297 } 298 299 buf.WriteString(fmt.Sprintf("%s\n", text)) 300 } 301 } 302 303 return strings.TrimSpace(buf.String()) 304 } 305 306 // RemoteState is used to track the information about a remote 307 // state store that we push/pull state to. 308 type RemoteState struct { 309 // Type controls the client we use for the remote state 310 Type string `json:"type"` 311 312 // Config is used to store arbitrary configuration that 313 // is type specific 314 Config map[string]string `json:"config"` 315 } 316 317 func (r *RemoteState) deepcopy() *RemoteState { 318 confCopy := make(map[string]string, len(r.Config)) 319 for k, v := range r.Config { 320 confCopy[k] = v 321 } 322 return &RemoteState{ 323 Type: r.Type, 324 Config: confCopy, 325 } 326 } 327 328 func (r *RemoteState) Empty() bool { 329 return r == nil || r.Type == "" 330 } 331 332 func (r *RemoteState) Equals(other *RemoteState) bool { 333 if r.Type != other.Type { 334 return false 335 } 336 if len(r.Config) != len(other.Config) { 337 return false 338 } 339 for k, v := range r.Config { 340 if other.Config[k] != v { 341 return false 342 } 343 } 344 return true 345 } 346 347 func (r *RemoteState) GoString() string { 348 return fmt.Sprintf("*%#v", *r) 349 } 350 351 // ModuleState is used to track all the state relevant to a single 352 // module. Previous to Terraform 0.3, all state belonged to the "root" 353 // module. 354 type ModuleState struct { 355 // Path is the import path from the root module. Modules imports are 356 // always disjoint, so the path represents amodule tree 357 Path []string `json:"path"` 358 359 // Outputs declared by the module and maintained for each module 360 // even though only the root module technically needs to be kept. 361 // This allows operators to inspect values at the boundaries. 362 Outputs map[string]string `json:"outputs"` 363 364 // Resources is a mapping of the logically named resource to 365 // the state of the resource. Each resource may actually have 366 // N instances underneath, although a user only needs to think 367 // about the 1:1 case. 368 Resources map[string]*ResourceState `json:"resources"` 369 370 // Dependencies are a list of things that this module relies on 371 // existing to remain intact. For example: an module may depend 372 // on a VPC ID given by an aws_vpc resource. 373 // 374 // Terraform uses this information to build valid destruction 375 // orders and to warn the user if they're destroying a module that 376 // another resource depends on. 377 // 378 // Things can be put into this list that may not be managed by 379 // Terraform. If Terraform doesn't find a matching ID in the 380 // overall state, then it assumes it isn't managed and doesn't 381 // worry about it. 382 Dependencies []string `json:"depends_on,omitempty"` 383 } 384 385 // Equal tests whether one module state is equal to another. 386 func (m *ModuleState) Equal(other *ModuleState) bool { 387 // Paths must be equal 388 if !reflect.DeepEqual(m.Path, other.Path) { 389 return false 390 } 391 392 // Outputs must be equal 393 if len(m.Outputs) != len(other.Outputs) { 394 return false 395 } 396 for k, v := range m.Outputs { 397 if other.Outputs[k] != v { 398 return false 399 } 400 } 401 402 // Dependencies must be equal. This sorts these in place but 403 // this shouldn't cause any problems. 404 sort.Strings(m.Dependencies) 405 sort.Strings(other.Dependencies) 406 if len(m.Dependencies) != len(other.Dependencies) { 407 return false 408 } 409 for i, d := range m.Dependencies { 410 if other.Dependencies[i] != d { 411 return false 412 } 413 } 414 415 // Resources must be equal 416 if len(m.Resources) != len(other.Resources) { 417 return false 418 } 419 for k, r := range m.Resources { 420 otherR, ok := other.Resources[k] 421 if !ok { 422 return false 423 } 424 425 if !r.Equal(otherR) { 426 return false 427 } 428 } 429 430 return true 431 } 432 433 // IsRoot says whether or not this module diff is for the root module. 434 func (m *ModuleState) IsRoot() bool { 435 return reflect.DeepEqual(m.Path, rootModulePath) 436 } 437 438 // Orphans returns a list of keys of resources that are in the State 439 // but aren't present in the configuration itself. Hence, these keys 440 // represent the state of resources that are orphans. 441 func (m *ModuleState) Orphans(c *config.Config) []string { 442 keys := make(map[string]struct{}) 443 for k, _ := range m.Resources { 444 keys[k] = struct{}{} 445 } 446 447 if c != nil { 448 for _, r := range c.Resources { 449 delete(keys, r.Id()) 450 451 for k, _ := range keys { 452 if strings.HasPrefix(k, r.Id()+".") { 453 delete(keys, k) 454 } 455 } 456 } 457 } 458 459 result := make([]string, 0, len(keys)) 460 for k, _ := range keys { 461 result = append(result, k) 462 } 463 464 return result 465 } 466 467 // View returns a view with the given resource prefix. 468 func (m *ModuleState) View(id string) *ModuleState { 469 if m == nil { 470 return m 471 } 472 473 r := m.deepcopy() 474 for k, _ := range r.Resources { 475 if id == k || strings.HasPrefix(k, id+".") { 476 continue 477 } 478 479 delete(r.Resources, k) 480 } 481 482 return r 483 } 484 485 func (m *ModuleState) init() { 486 if m.Outputs == nil { 487 m.Outputs = make(map[string]string) 488 } 489 if m.Resources == nil { 490 m.Resources = make(map[string]*ResourceState) 491 } 492 } 493 494 func (m *ModuleState) deepcopy() *ModuleState { 495 if m == nil { 496 return nil 497 } 498 n := &ModuleState{ 499 Path: make([]string, len(m.Path)), 500 Outputs: make(map[string]string, len(m.Outputs)), 501 Resources: make(map[string]*ResourceState, len(m.Resources)), 502 } 503 copy(n.Path, m.Path) 504 for k, v := range m.Outputs { 505 n.Outputs[k] = v 506 } 507 for k, v := range m.Resources { 508 n.Resources[k] = v.deepcopy() 509 } 510 return n 511 } 512 513 // prune is used to remove any resources that are no longer required 514 func (m *ModuleState) prune() { 515 for k, v := range m.Resources { 516 v.prune() 517 518 if (v.Primary == nil || v.Primary.ID == "") && len(v.Tainted) == 0 && len(v.Deposed) == 0 { 519 delete(m.Resources, k) 520 } 521 } 522 523 for k, v := range m.Outputs { 524 if v == config.UnknownVariableValue { 525 delete(m.Outputs, k) 526 } 527 } 528 } 529 530 func (m *ModuleState) sort() { 531 for _, v := range m.Resources { 532 v.sort() 533 } 534 } 535 536 func (m *ModuleState) GoString() string { 537 return fmt.Sprintf("*%#v", *m) 538 } 539 540 func (m *ModuleState) String() string { 541 var buf bytes.Buffer 542 543 if len(m.Resources) == 0 { 544 buf.WriteString("<no state>") 545 } 546 547 names := make([]string, 0, len(m.Resources)) 548 for name, _ := range m.Resources { 549 names = append(names, name) 550 } 551 sort.Strings(names) 552 553 for _, k := range names { 554 rs := m.Resources[k] 555 var id string 556 if rs.Primary != nil { 557 id = rs.Primary.ID 558 } 559 if id == "" { 560 id = "<not created>" 561 } 562 563 taintStr := "" 564 if len(rs.Tainted) > 0 { 565 taintStr = fmt.Sprintf(" (%d tainted)", len(rs.Tainted)) 566 } 567 568 deposedStr := "" 569 if len(rs.Deposed) > 0 { 570 deposedStr = fmt.Sprintf(" (%d deposed)", len(rs.Deposed)) 571 } 572 573 buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr)) 574 buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) 575 576 var attributes map[string]string 577 if rs.Primary != nil { 578 attributes = rs.Primary.Attributes 579 } 580 attrKeys := make([]string, 0, len(attributes)) 581 for ak, _ := range attributes { 582 if ak == "id" { 583 continue 584 } 585 586 attrKeys = append(attrKeys, ak) 587 } 588 sort.Strings(attrKeys) 589 590 for _, ak := range attrKeys { 591 av := attributes[ak] 592 buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) 593 } 594 595 for idx, t := range rs.Tainted { 596 buf.WriteString(fmt.Sprintf(" Tainted ID %d = %s\n", idx+1, t.ID)) 597 } 598 599 for idx, t := range rs.Deposed { 600 buf.WriteString(fmt.Sprintf(" Deposed ID %d = %s\n", idx+1, t.ID)) 601 } 602 603 if len(rs.Dependencies) > 0 { 604 buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) 605 for _, dep := range rs.Dependencies { 606 buf.WriteString(fmt.Sprintf(" %s\n", dep)) 607 } 608 } 609 } 610 611 if len(m.Outputs) > 0 { 612 buf.WriteString("\nOutputs:\n\n") 613 614 ks := make([]string, 0, len(m.Outputs)) 615 for k, _ := range m.Outputs { 616 ks = append(ks, k) 617 } 618 sort.Strings(ks) 619 620 for _, k := range ks { 621 v := m.Outputs[k] 622 buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) 623 } 624 } 625 626 return buf.String() 627 } 628 629 // ResourceState holds the state of a resource that is used so that 630 // a provider can find and manage an existing resource as well as for 631 // storing attributes that are used to populate variables of child 632 // resources. 633 // 634 // Attributes has attributes about the created resource that are 635 // queryable in interpolation: "${type.id.attr}" 636 // 637 // Extra is just extra data that a provider can return that we store 638 // for later, but is not exposed in any way to the user. 639 // 640 type ResourceState struct { 641 // This is filled in and managed by Terraform, and is the resource 642 // type itself such as "mycloud_instance". If a resource provider sets 643 // this value, it won't be persisted. 644 Type string `json:"type"` 645 646 // Dependencies are a list of things that this resource relies on 647 // existing to remain intact. For example: an AWS instance might 648 // depend on a subnet (which itself might depend on a VPC, and so 649 // on). 650 // 651 // Terraform uses this information to build valid destruction 652 // orders and to warn the user if they're destroying a resource that 653 // another resource depends on. 654 // 655 // Things can be put into this list that may not be managed by 656 // Terraform. If Terraform doesn't find a matching ID in the 657 // overall state, then it assumes it isn't managed and doesn't 658 // worry about it. 659 Dependencies []string `json:"depends_on,omitempty"` 660 661 // Primary is the current active instance for this resource. 662 // It can be replaced but only after a successful creation. 663 // This is the instances on which providers will act. 664 Primary *InstanceState `json:"primary"` 665 666 // Tainted is used to track any underlying instances that 667 // have been created but are in a bad or unknown state and 668 // need to be cleaned up subsequently. In the 669 // standard case, there is only at most a single instance. 670 // However, in pathological cases, it is possible for the number 671 // of instances to accumulate. 672 Tainted []*InstanceState `json:"tainted,omitempty"` 673 674 // Deposed is used in the mechanics of CreateBeforeDestroy: the existing 675 // Primary is Deposed to get it out of the way for the replacement Primary to 676 // be created by Apply. If the replacement Primary creates successfully, the 677 // Deposed instance is cleaned up. If there were problems creating the 678 // replacement, the instance remains in the Deposed list so it can be 679 // destroyed in a future run. Functionally, Deposed instances are very 680 // similar to Tainted instances in that Terraform is only tracking them in 681 // order to remember to destroy them. 682 Deposed []*InstanceState `json:"deposed,omitempty"` 683 } 684 685 // Equal tests whether two ResourceStates are equal. 686 func (s *ResourceState) Equal(other *ResourceState) bool { 687 if s.Type != other.Type { 688 return false 689 } 690 691 // Dependencies must be equal 692 sort.Strings(s.Dependencies) 693 sort.Strings(other.Dependencies) 694 if len(s.Dependencies) != len(other.Dependencies) { 695 return false 696 } 697 for i, d := range s.Dependencies { 698 if other.Dependencies[i] != d { 699 return false 700 } 701 } 702 703 // States must be equal 704 if !s.Primary.Equal(other.Primary) { 705 return false 706 } 707 708 // Tainted 709 taints := make(map[string]*InstanceState) 710 for _, t := range other.Tainted { 711 if t == nil { 712 continue 713 } 714 715 taints[t.ID] = t 716 } 717 for _, t := range s.Tainted { 718 if t == nil { 719 continue 720 } 721 722 otherT, ok := taints[t.ID] 723 if !ok { 724 return false 725 } 726 delete(taints, t.ID) 727 728 if !t.Equal(otherT) { 729 return false 730 } 731 } 732 733 // This means that we have stuff in other tainted that we don't 734 // have, so it is not equal. 735 if len(taints) > 0 { 736 return false 737 } 738 739 return true 740 } 741 742 // Taint takes the primary state and marks it as tainted. If there is no 743 // primary state, this does nothing. 744 func (r *ResourceState) Taint() { 745 // If there is no primary, nothing to do 746 if r.Primary == nil { 747 return 748 } 749 750 // Shuffle to the end of the taint list and set primary to nil 751 r.Tainted = append(r.Tainted, r.Primary) 752 r.Primary = nil 753 } 754 755 func (r *ResourceState) init() { 756 if r.Primary == nil { 757 r.Primary = &InstanceState{} 758 } 759 r.Primary.init() 760 } 761 762 func (r *ResourceState) deepcopy() *ResourceState { 763 if r == nil { 764 return nil 765 } 766 767 n := &ResourceState{ 768 Type: r.Type, 769 Dependencies: nil, 770 Primary: r.Primary.deepcopy(), 771 Tainted: nil, 772 } 773 if r.Dependencies != nil { 774 n.Dependencies = make([]string, len(r.Dependencies)) 775 copy(n.Dependencies, r.Dependencies) 776 } 777 if r.Tainted != nil { 778 n.Tainted = make([]*InstanceState, 0, len(r.Tainted)) 779 for _, inst := range r.Tainted { 780 n.Tainted = append(n.Tainted, inst.deepcopy()) 781 } 782 } 783 if r.Deposed != nil { 784 n.Deposed = make([]*InstanceState, 0, len(r.Deposed)) 785 for _, inst := range r.Deposed { 786 n.Deposed = append(n.Deposed, inst.deepcopy()) 787 } 788 } 789 790 return n 791 } 792 793 // prune is used to remove any instances that are no longer required 794 func (r *ResourceState) prune() { 795 n := len(r.Tainted) 796 for i := 0; i < n; i++ { 797 inst := r.Tainted[i] 798 if inst == nil || inst.ID == "" { 799 copy(r.Tainted[i:], r.Tainted[i+1:]) 800 r.Tainted[n-1] = nil 801 n-- 802 i-- 803 } 804 } 805 806 r.Tainted = r.Tainted[:n] 807 808 n = len(r.Deposed) 809 for i := 0; i < n; i++ { 810 inst := r.Deposed[i] 811 if inst == nil || inst.ID == "" { 812 copy(r.Deposed[i:], r.Deposed[i+1:]) 813 r.Deposed[n-1] = nil 814 n-- 815 i-- 816 } 817 } 818 819 r.Deposed = r.Deposed[:n] 820 } 821 822 func (r *ResourceState) sort() { 823 sort.Strings(r.Dependencies) 824 } 825 826 func (s *ResourceState) GoString() string { 827 return fmt.Sprintf("*%#v", *s) 828 } 829 830 func (s *ResourceState) String() string { 831 var buf bytes.Buffer 832 buf.WriteString(fmt.Sprintf("Type = %s", s.Type)) 833 return buf.String() 834 } 835 836 // InstanceState is used to track the unique state information belonging 837 // to a given instance. 838 type InstanceState struct { 839 // A unique ID for this resource. This is opaque to Terraform 840 // and is only meant as a lookup mechanism for the providers. 841 ID string `json:"id"` 842 843 // Attributes are basic information about the resource. Any keys here 844 // are accessible in variable format within Terraform configurations: 845 // ${resourcetype.name.attribute}. 846 Attributes map[string]string `json:"attributes,omitempty"` 847 848 // Ephemeral is used to store any state associated with this instance 849 // that is necessary for the Terraform run to complete, but is not 850 // persisted to a state file. 851 Ephemeral EphemeralState `json:"-"` 852 853 // Meta is a simple K/V map that is persisted to the State but otherwise 854 // ignored by Terraform core. It's meant to be used for accounting by 855 // external client code. 856 Meta map[string]string `json:"meta,omitempty"` 857 } 858 859 func (i *InstanceState) init() { 860 if i.Attributes == nil { 861 i.Attributes = make(map[string]string) 862 } 863 if i.Meta == nil { 864 i.Meta = make(map[string]string) 865 } 866 i.Ephemeral.init() 867 } 868 869 func (i *InstanceState) deepcopy() *InstanceState { 870 if i == nil { 871 return nil 872 } 873 n := &InstanceState{ 874 ID: i.ID, 875 Ephemeral: *i.Ephemeral.deepcopy(), 876 } 877 if i.Attributes != nil { 878 n.Attributes = make(map[string]string, len(i.Attributes)) 879 for k, v := range i.Attributes { 880 n.Attributes[k] = v 881 } 882 } 883 if i.Meta != nil { 884 n.Meta = make(map[string]string, len(i.Meta)) 885 for k, v := range i.Meta { 886 n.Meta[k] = v 887 } 888 } 889 return n 890 } 891 892 func (s *InstanceState) Empty() bool { 893 return s == nil || s.ID == "" 894 } 895 896 func (s *InstanceState) Equal(other *InstanceState) bool { 897 // Short circuit some nil checks 898 if s == nil || other == nil { 899 return s == other 900 } 901 902 // IDs must be equal 903 if s.ID != other.ID { 904 return false 905 } 906 907 // Attributes must be equal 908 if len(s.Attributes) != len(other.Attributes) { 909 return false 910 } 911 for k, v := range s.Attributes { 912 otherV, ok := other.Attributes[k] 913 if !ok { 914 return false 915 } 916 917 if v != otherV { 918 return false 919 } 920 } 921 922 return true 923 } 924 925 // MergeDiff takes a ResourceDiff and merges the attributes into 926 // this resource state in order to generate a new state. This new 927 // state can be used to provide updated attribute lookups for 928 // variable interpolation. 929 // 930 // If the diff attribute requires computing the value, and hence 931 // won't be available until apply, the value is replaced with the 932 // computeID. 933 func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { 934 result := s.deepcopy() 935 if result == nil { 936 result = new(InstanceState) 937 } 938 result.init() 939 940 if s != nil { 941 for k, v := range s.Attributes { 942 result.Attributes[k] = v 943 } 944 } 945 if d != nil { 946 for k, diff := range d.Attributes { 947 if diff.NewRemoved { 948 delete(result.Attributes, k) 949 continue 950 } 951 if diff.NewComputed { 952 result.Attributes[k] = config.UnknownVariableValue 953 continue 954 } 955 956 result.Attributes[k] = diff.New 957 } 958 } 959 960 return result 961 } 962 963 func (i *InstanceState) GoString() string { 964 return fmt.Sprintf("*%#v", *i) 965 } 966 967 func (i *InstanceState) String() string { 968 var buf bytes.Buffer 969 970 if i == nil || i.ID == "" { 971 return "<not created>" 972 } 973 974 buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID)) 975 976 attributes := i.Attributes 977 attrKeys := make([]string, 0, len(attributes)) 978 for ak, _ := range attributes { 979 if ak == "id" { 980 continue 981 } 982 983 attrKeys = append(attrKeys, ak) 984 } 985 sort.Strings(attrKeys) 986 987 for _, ak := range attrKeys { 988 av := attributes[ak] 989 buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av)) 990 } 991 992 return buf.String() 993 } 994 995 // EphemeralState is used for transient state that is only kept in-memory 996 type EphemeralState struct { 997 // ConnInfo is used for the providers to export information which is 998 // used to connect to the resource for provisioning. For example, 999 // this could contain SSH or WinRM credentials. 1000 ConnInfo map[string]string `json:"-"` 1001 } 1002 1003 func (e *EphemeralState) init() { 1004 if e.ConnInfo == nil { 1005 e.ConnInfo = make(map[string]string) 1006 } 1007 } 1008 1009 func (e *EphemeralState) deepcopy() *EphemeralState { 1010 if e == nil { 1011 return nil 1012 } 1013 n := &EphemeralState{} 1014 if e.ConnInfo != nil { 1015 n.ConnInfo = make(map[string]string, len(e.ConnInfo)) 1016 for k, v := range e.ConnInfo { 1017 n.ConnInfo[k] = v 1018 } 1019 } 1020 return n 1021 } 1022 1023 // ReadState reads a state structure out of a reader in the format that 1024 // was written by WriteState. 1025 func ReadState(src io.Reader) (*State, error) { 1026 buf := bufio.NewReader(src) 1027 1028 // Check if this is a V1 format 1029 start, err := buf.Peek(len(stateFormatMagic)) 1030 if err != nil { 1031 return nil, fmt.Errorf("Failed to check for magic bytes: %v", err) 1032 } 1033 if string(start) == stateFormatMagic { 1034 // Read the old state 1035 old, err := ReadStateV1(buf) 1036 if err != nil { 1037 return nil, err 1038 } 1039 return upgradeV1State(old) 1040 } 1041 1042 // Otherwise, must be V2 1043 dec := json.NewDecoder(buf) 1044 state := &State{} 1045 if err := dec.Decode(state); err != nil { 1046 return nil, fmt.Errorf("Decoding state file failed: %v", err) 1047 } 1048 1049 // Check the version, this to ensure we don't read a future 1050 // version that we don't understand 1051 if state.Version > StateVersion { 1052 return nil, fmt.Errorf("State version %d not supported, please update.", 1053 state.Version) 1054 } 1055 1056 // Sort it 1057 state.sort() 1058 1059 return state, nil 1060 } 1061 1062 // WriteState writes a state somewhere in a binary format. 1063 func WriteState(d *State, dst io.Writer) error { 1064 // Make sure it is sorted 1065 d.sort() 1066 1067 // Ensure the version is set 1068 d.Version = StateVersion 1069 1070 // Encode the data in a human-friendly way 1071 data, err := json.MarshalIndent(d, "", " ") 1072 if err != nil { 1073 return fmt.Errorf("Failed to encode state: %s", err) 1074 } 1075 1076 // We append a newline to the data because MarshalIndent doesn't 1077 data = append(data, '\n') 1078 1079 // Write the data out to the dst 1080 if _, err := io.Copy(dst, bytes.NewReader(data)); err != nil { 1081 return fmt.Errorf("Failed to write state: %v", err) 1082 } 1083 1084 return nil 1085 } 1086 1087 // upgradeV1State is used to upgrade a V1 state representation 1088 // into a proper State representation. 1089 func upgradeV1State(old *StateV1) (*State, error) { 1090 s := &State{} 1091 s.init() 1092 1093 // Old format had no modules, so we migrate everything 1094 // directly into the root module. 1095 root := s.RootModule() 1096 1097 // Copy the outputs 1098 root.Outputs = old.Outputs 1099 1100 // Upgrade the resources 1101 for id, rs := range old.Resources { 1102 newRs := &ResourceState{ 1103 Type: rs.Type, 1104 } 1105 root.Resources[id] = newRs 1106 1107 // Migrate to an instance state 1108 instance := &InstanceState{ 1109 ID: rs.ID, 1110 Attributes: rs.Attributes, 1111 } 1112 1113 // Check if this is the primary or tainted instance 1114 if _, ok := old.Tainted[id]; ok { 1115 newRs.Tainted = append(newRs.Tainted, instance) 1116 } else { 1117 newRs.Primary = instance 1118 } 1119 1120 // Warn if the resource uses Extra, as there is 1121 // no upgrade path for this! Now totally deprecated. 1122 if len(rs.Extra) > 0 { 1123 log.Printf( 1124 "[WARN] Resource %s uses deprecated attribute "+ 1125 "storage, state file upgrade may be incomplete.", 1126 rs.ID, 1127 ) 1128 } 1129 } 1130 return s, nil 1131 } 1132 1133 // moduleStateSort implements sort.Interface to sort module states 1134 type moduleStateSort []*ModuleState 1135 1136 func (s moduleStateSort) Len() int { 1137 return len(s) 1138 } 1139 1140 func (s moduleStateSort) Less(i, j int) bool { 1141 a := s[i] 1142 b := s[j] 1143 1144 // If the lengths are different, then the shorter one always wins 1145 if len(a.Path) != len(b.Path) { 1146 return len(a.Path) < len(b.Path) 1147 } 1148 1149 // Otherwise, compare by last path element 1150 idx := len(a.Path) - 1 1151 return a.Path[idx] < b.Path[idx] 1152 } 1153 1154 func (s moduleStateSort) Swap(i, j int) { 1155 s[i], s[j] = s[j], s[i] 1156 }