github.com/memsql/terraform@v0.7.0-rc2.0.20160706152241-21e2173e0a32/terraform/state.go (about) 1 package terraform 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "log" 11 "reflect" 12 "sort" 13 "strconv" 14 "strings" 15 16 "github.com/hashicorp/go-version" 17 "github.com/satori/go.uuid" 18 19 "github.com/hashicorp/terraform/config" 20 "github.com/mitchellh/copystructure" 21 ) 22 23 const ( 24 // StateVersion is the current version for our state file 25 StateVersion = 3 26 ) 27 28 // rootModulePath is the path of the root module 29 var rootModulePath = []string{"root"} 30 31 // normalizeModulePath takes a raw module path and returns a path that 32 // has the rootModulePath prepended to it. If I could go back in time I 33 // would've never had a rootModulePath (empty path would be root). We can 34 // still fix this but thats a big refactor that my branch doesn't make sense 35 // for. Instead, this function normalizes paths. 36 func normalizeModulePath(p []string) []string { 37 k := len(rootModulePath) 38 39 // If we already have a root module prefix, we're done 40 if len(p) >= len(rootModulePath) { 41 if reflect.DeepEqual(p[:k], rootModulePath) { 42 return p 43 } 44 } 45 46 // None? Prefix it 47 result := make([]string, len(rootModulePath)+len(p)) 48 copy(result, rootModulePath) 49 copy(result[k:], p) 50 return result 51 } 52 53 // State keeps track of a snapshot state-of-the-world that Terraform 54 // can use to keep track of what real world resources it is actually 55 // managing. This is the latest format as of Terraform 0.3 56 type State struct { 57 // Version is the protocol version. Currently only "1". 58 Version int `json:"version"` 59 60 // TFVersion is the version of Terraform that wrote this state. 61 TFVersion string `json:"terraform_version,omitempty"` 62 63 // Serial is incremented on any operation that modifies 64 // the State file. It is used to detect potentially conflicting 65 // updates. 66 Serial int64 `json:"serial"` 67 68 // Lineage is set when a new, blank state is created and then 69 // never updated. This allows us to determine whether the serials 70 // of two states can be meaningfully compared. 71 // Apart from the guarantee that collisions between two lineages 72 // are very unlikely, this value is opaque and external callers 73 // should only compare lineage strings byte-for-byte for equality. 74 Lineage string `json:"lineage,omitempty"` 75 76 // Remote is used to track the metadata required to 77 // pull and push state files from a remote storage endpoint. 78 Remote *RemoteState `json:"remote,omitempty"` 79 80 // Modules contains all the modules in a breadth-first order 81 Modules []*ModuleState `json:"modules"` 82 } 83 84 // NewState is used to initialize a blank state 85 func NewState() *State { 86 s := &State{} 87 s.init() 88 return s 89 } 90 91 // Children returns the ModuleStates that are direct children of 92 // the given path. If the path is "root", for example, then children 93 // returned might be "root.child", but not "root.child.grandchild". 94 func (s *State) Children(path []string) []*ModuleState { 95 // TODO: test 96 97 result := make([]*ModuleState, 0) 98 for _, m := range s.Modules { 99 if len(m.Path) != len(path)+1 { 100 continue 101 } 102 if !reflect.DeepEqual(path, m.Path[:len(path)]) { 103 continue 104 } 105 106 result = append(result, m) 107 } 108 109 return result 110 } 111 112 // AddModule adds the module with the given path to the state. 113 // 114 // This should be the preferred method to add module states since it 115 // allows us to optimize lookups later as well as control sorting. 116 func (s *State) AddModule(path []string) *ModuleState { 117 m := &ModuleState{Path: path} 118 m.init() 119 s.Modules = append(s.Modules, m) 120 s.sort() 121 return m 122 } 123 124 // ModuleByPath is used to lookup the module state for the given path. 125 // This should be the preferred lookup mechanism as it allows for future 126 // lookup optimizations. 127 func (s *State) ModuleByPath(path []string) *ModuleState { 128 if s == nil { 129 return nil 130 } 131 for _, mod := range s.Modules { 132 if mod.Path == nil { 133 panic("missing module path") 134 } 135 if reflect.DeepEqual(mod.Path, path) { 136 return mod 137 } 138 } 139 return nil 140 } 141 142 // ModuleOrphans returns all the module orphans in this state by 143 // returning their full paths. These paths can be used with ModuleByPath 144 // to return the actual state. 145 func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { 146 // direct keeps track of what direct children we have both in our config 147 // and in our state. childrenKeys keeps track of what isn't an orphan. 148 direct := make(map[string]struct{}) 149 childrenKeys := make(map[string]struct{}) 150 if c != nil { 151 for _, m := range c.Modules { 152 childrenKeys[m.Name] = struct{}{} 153 direct[m.Name] = struct{}{} 154 } 155 } 156 157 // Go over the direct children and find any that aren't in our keys. 158 var orphans [][]string 159 for _, m := range s.Children(path) { 160 key := m.Path[len(m.Path)-1] 161 162 // Record that we found this key as a direct child. We use this 163 // later to find orphan nested modules. 164 direct[key] = struct{}{} 165 166 // If we have a direct child still in our config, it is not an orphan 167 if _, ok := childrenKeys[key]; ok { 168 continue 169 } 170 171 orphans = append(orphans, m.Path) 172 } 173 174 // Find the orphans that are nested... 175 for _, m := range s.Modules { 176 // We only want modules that are at least grandchildren 177 if len(m.Path) < len(path)+2 { 178 continue 179 } 180 181 // If it isn't part of our tree, continue 182 if !reflect.DeepEqual(path, m.Path[:len(path)]) { 183 continue 184 } 185 186 // If we have the direct child, then just skip it. 187 key := m.Path[len(path)] 188 if _, ok := direct[key]; ok { 189 continue 190 } 191 192 orphanPath := m.Path[:len(path)+1] 193 194 // Don't double-add if we've already added this orphan (which can happen if 195 // there are multiple nested sub-modules that get orphaned together). 196 alreadyAdded := false 197 for _, o := range orphans { 198 if reflect.DeepEqual(o, orphanPath) { 199 alreadyAdded = true 200 break 201 } 202 } 203 if alreadyAdded { 204 continue 205 } 206 207 // Add this orphan 208 orphans = append(orphans, orphanPath) 209 } 210 211 return orphans 212 } 213 214 // Empty returns true if the state is empty. 215 func (s *State) Empty() bool { 216 if s == nil { 217 return true 218 } 219 220 return len(s.Modules) == 0 221 } 222 223 // IsRemote returns true if State represents a state that exists and is 224 // remote. 225 func (s *State) IsRemote() bool { 226 if s == nil { 227 return false 228 } 229 if s.Remote == nil { 230 return false 231 } 232 if s.Remote.Type == "" { 233 return false 234 } 235 236 return true 237 } 238 239 // Remove removes the item in the state at the given address, returning 240 // any errors that may have occurred. 241 // 242 // If the address references a module state or resource, it will delete 243 // all children as well. To check what will be deleted, use a StateFilter 244 // first. 245 func (s *State) Remove(addr ...string) error { 246 // Filter out what we need to delete 247 filter := &StateFilter{State: s} 248 results, err := filter.Filter(addr...) 249 if err != nil { 250 return err 251 } 252 253 // If we have no results, just exit early, we're not going to do anything. 254 // While what happens below is fairly fast, this is an important early 255 // exit since the prune below might modify the state more and we don't 256 // want to modify the state if we don't have to. 257 if len(results) == 0 { 258 return nil 259 } 260 261 // Go through each result and grab what we need 262 removed := make(map[interface{}]struct{}) 263 for _, r := range results { 264 // Convert the path to our own type 265 path := append([]string{"root"}, r.Path...) 266 267 // If we removed this already, then ignore 268 if _, ok := removed[r.Value]; ok { 269 continue 270 } 271 272 // If we removed the parent already, then ignore 273 if r.Parent != nil { 274 if _, ok := removed[r.Parent.Value]; ok { 275 continue 276 } 277 } 278 279 // Add this to the removed list 280 removed[r.Value] = struct{}{} 281 282 switch v := r.Value.(type) { 283 case *ModuleState: 284 s.removeModule(path, v) 285 case *ResourceState: 286 s.removeResource(path, v) 287 case *InstanceState: 288 s.removeInstance(path, r.Parent.Value.(*ResourceState), v) 289 default: 290 return fmt.Errorf("unknown type to delete: %T", r.Value) 291 } 292 } 293 294 // Prune since the removal functions often do the bare minimum to 295 // remove a thing and may leave around dangling empty modules, resources, 296 // etc. Prune will clean that all up. 297 s.prune() 298 299 return nil 300 } 301 302 func (s *State) removeModule(path []string, v *ModuleState) { 303 for i, m := range s.Modules { 304 if m == v { 305 s.Modules, s.Modules[len(s.Modules)-1] = append(s.Modules[:i], s.Modules[i+1:]...), nil 306 return 307 } 308 } 309 } 310 311 func (s *State) removeResource(path []string, v *ResourceState) { 312 // Get the module this resource lives in. If it doesn't exist, we're done. 313 mod := s.ModuleByPath(path) 314 if mod == nil { 315 return 316 } 317 318 // Find this resource. This is a O(N) lookup when if we had the key 319 // it could be O(1) but even with thousands of resources this shouldn't 320 // matter right now. We can easily up performance here when the time comes. 321 for k, r := range mod.Resources { 322 if r == v { 323 // Found it 324 delete(mod.Resources, k) 325 return 326 } 327 } 328 } 329 330 func (s *State) removeInstance(path []string, r *ResourceState, v *InstanceState) { 331 // Go through the resource and find the instance that matches this 332 // (if any) and remove it. 333 334 // Check primary 335 if r.Primary == v { 336 r.Primary = nil 337 return 338 } 339 340 // Check lists 341 lists := [][]*InstanceState{r.Deposed} 342 for _, is := range lists { 343 for i, instance := range is { 344 if instance == v { 345 // Found it, remove it 346 is, is[len(is)-1] = append(is[:i], is[i+1:]...), nil 347 348 // Done 349 return 350 } 351 } 352 } 353 } 354 355 // RootModule returns the ModuleState for the root module 356 func (s *State) RootModule() *ModuleState { 357 root := s.ModuleByPath(rootModulePath) 358 if root == nil { 359 panic("missing root module") 360 } 361 return root 362 } 363 364 // Equal tests if one state is equal to another. 365 func (s *State) Equal(other *State) bool { 366 // If one is nil, we do a direct check 367 if s == nil || other == nil { 368 return s == other 369 } 370 371 // If the versions are different, they're certainly not equal 372 if s.Version != other.Version { 373 return false 374 } 375 376 // If any of the modules are not equal, then this state isn't equal 377 if len(s.Modules) != len(other.Modules) { 378 return false 379 } 380 for _, m := range s.Modules { 381 // This isn't very optimal currently but works. 382 otherM := other.ModuleByPath(m.Path) 383 if otherM == nil { 384 return false 385 } 386 387 // If they're not equal, then we're not equal! 388 if !m.Equal(otherM) { 389 return false 390 } 391 } 392 393 return true 394 } 395 396 type StateAgeComparison int 397 398 const ( 399 StateAgeEqual StateAgeComparison = 0 400 StateAgeReceiverNewer StateAgeComparison = 1 401 StateAgeReceiverOlder StateAgeComparison = -1 402 ) 403 404 // CompareAges compares one state with another for which is "older". 405 // 406 // This is a simple check using the state's serial, and is thus only as 407 // reliable as the serial itself. In the normal case, only one state 408 // exists for a given combination of lineage/serial, but Terraform 409 // does not guarantee this and so the result of this method should be 410 // used with care. 411 // 412 // Returns an integer that is negative if the receiver is older than 413 // the argument, positive if the converse, and zero if they are equal. 414 // An error is returned if the two states are not of the same lineage, 415 // in which case the integer returned has no meaning. 416 func (s *State) CompareAges(other *State) (StateAgeComparison, error) { 417 418 // nil states are "older" than actual states 419 switch { 420 case s != nil && other == nil: 421 return StateAgeReceiverNewer, nil 422 case s == nil && other != nil: 423 return StateAgeReceiverOlder, nil 424 case s == nil && other == nil: 425 return StateAgeEqual, nil 426 } 427 428 if !s.SameLineage(other) { 429 return StateAgeEqual, fmt.Errorf( 430 "can't compare two states of differing lineage", 431 ) 432 } 433 434 switch { 435 case s.Serial < other.Serial: 436 return StateAgeReceiverOlder, nil 437 case s.Serial > other.Serial: 438 return StateAgeReceiverNewer, nil 439 default: 440 return StateAgeEqual, nil 441 } 442 } 443 444 // SameLineage returns true only if the state given in argument belongs 445 // to the same "lineage" of states as the reciever. 446 func (s *State) SameLineage(other *State) bool { 447 // If one of the states has no lineage then it is assumed to predate 448 // this concept, and so we'll accept it as belonging to any lineage 449 // so that a lineage string can be assigned to newer versions 450 // without breaking compatibility with older versions. 451 if s.Lineage == "" || other.Lineage == "" { 452 return true 453 } 454 455 return s.Lineage == other.Lineage 456 } 457 458 // DeepCopy performs a deep copy of the state structure and returns 459 // a new structure. 460 func (s *State) DeepCopy() *State { 461 copy, err := copystructure.Copy(s) 462 if err != nil { 463 panic(err) 464 } 465 466 return copy.(*State) 467 } 468 469 // IncrementSerialMaybe increments the serial number of this state 470 // if it different from the other state. 471 func (s *State) IncrementSerialMaybe(other *State) { 472 if s == nil { 473 return 474 } 475 if other == nil { 476 return 477 } 478 if s.Serial > other.Serial { 479 return 480 } 481 if other.TFVersion != s.TFVersion || !s.Equal(other) { 482 if other.Serial > s.Serial { 483 s.Serial = other.Serial 484 } 485 486 s.Serial++ 487 } 488 } 489 490 // FromFutureTerraform checks if this state was written by a Terraform 491 // version from the future. 492 func (s *State) FromFutureTerraform() bool { 493 // No TF version means it is certainly from the past 494 if s.TFVersion == "" { 495 return false 496 } 497 498 v := version.Must(version.NewVersion(s.TFVersion)) 499 return SemVersion.LessThan(v) 500 } 501 502 func (s *State) init() { 503 if s.Version == 0 { 504 s.Version = StateVersion 505 } 506 if s.ModuleByPath(rootModulePath) == nil { 507 s.AddModule(rootModulePath) 508 } 509 s.EnsureHasLineage() 510 } 511 512 func (s *State) EnsureHasLineage() { 513 if s.Lineage == "" { 514 s.Lineage = uuid.NewV4().String() 515 log.Printf("[DEBUG] New state was assigned lineage %q\n", s.Lineage) 516 } else { 517 log.Printf("[TRACE] Preserving existing state lineage %q\n", s.Lineage) 518 } 519 } 520 521 // prune is used to remove any resources that are no longer required 522 func (s *State) prune() { 523 if s == nil { 524 return 525 } 526 for _, mod := range s.Modules { 527 mod.prune() 528 } 529 if s.Remote != nil && s.Remote.Empty() { 530 s.Remote = nil 531 } 532 } 533 534 // sort sorts the modules 535 func (s *State) sort() { 536 sort.Sort(moduleStateSort(s.Modules)) 537 538 // Allow modules to be sorted 539 for _, m := range s.Modules { 540 m.sort() 541 } 542 } 543 544 func (s *State) GoString() string { 545 return fmt.Sprintf("*%#v", *s) 546 } 547 548 func (s *State) String() string { 549 if s == nil { 550 return "<nil>" 551 } 552 553 var buf bytes.Buffer 554 for _, m := range s.Modules { 555 mStr := m.String() 556 557 // If we're the root module, we just write the output directly. 558 if reflect.DeepEqual(m.Path, rootModulePath) { 559 buf.WriteString(mStr + "\n") 560 continue 561 } 562 563 buf.WriteString(fmt.Sprintf("module.%s:\n", strings.Join(m.Path[1:], "."))) 564 565 s := bufio.NewScanner(strings.NewReader(mStr)) 566 for s.Scan() { 567 text := s.Text() 568 if text != "" { 569 text = " " + text 570 } 571 572 buf.WriteString(fmt.Sprintf("%s\n", text)) 573 } 574 } 575 576 return strings.TrimSpace(buf.String()) 577 } 578 579 // RemoteState is used to track the information about a remote 580 // state store that we push/pull state to. 581 type RemoteState struct { 582 // Type controls the client we use for the remote state 583 Type string `json:"type"` 584 585 // Config is used to store arbitrary configuration that 586 // is type specific 587 Config map[string]string `json:"config"` 588 } 589 590 func (r *RemoteState) deepcopy() *RemoteState { 591 confCopy := make(map[string]string, len(r.Config)) 592 for k, v := range r.Config { 593 confCopy[k] = v 594 } 595 return &RemoteState{ 596 Type: r.Type, 597 Config: confCopy, 598 } 599 } 600 601 func (r *RemoteState) Empty() bool { 602 return r == nil || r.Type == "" 603 } 604 605 func (r *RemoteState) Equals(other *RemoteState) bool { 606 if r.Type != other.Type { 607 return false 608 } 609 if len(r.Config) != len(other.Config) { 610 return false 611 } 612 for k, v := range r.Config { 613 if other.Config[k] != v { 614 return false 615 } 616 } 617 return true 618 } 619 620 func (r *RemoteState) GoString() string { 621 return fmt.Sprintf("*%#v", *r) 622 } 623 624 // OutputState is used to track the state relevant to a single output. 625 type OutputState struct { 626 // Sensitive describes whether the output is considered sensitive, 627 // which may lead to masking the value on screen in some cases. 628 Sensitive bool `json:"sensitive"` 629 // Type describes the structure of Value. Valid values are "string", 630 // "map" and "list" 631 Type string `json:"type"` 632 // Value contains the value of the output, in the structure described 633 // by the Type field. 634 Value interface{} `json:"value"` 635 } 636 637 func (s *OutputState) String() string { 638 return fmt.Sprintf("%#v", s.Value) 639 } 640 641 // Equal compares two OutputState structures for equality. nil values are 642 // considered equal. 643 func (s *OutputState) Equal(other *OutputState) bool { 644 if s == nil && other == nil { 645 return true 646 } 647 648 if s == nil || other == nil { 649 return false 650 } 651 652 if s.Type != other.Type { 653 return false 654 } 655 656 if s.Sensitive != other.Sensitive { 657 return false 658 } 659 660 if !reflect.DeepEqual(s.Value, other.Value) { 661 return false 662 } 663 664 return true 665 } 666 667 func (s *OutputState) deepcopy() *OutputState { 668 if s == nil { 669 return nil 670 } 671 672 valueCopy, err := copystructure.Copy(s.Value) 673 if err != nil { 674 panic(fmt.Errorf("Error copying output value: %s", err)) 675 } 676 677 n := &OutputState{ 678 Type: s.Type, 679 Sensitive: s.Sensitive, 680 Value: valueCopy, 681 } 682 683 return n 684 } 685 686 // ModuleState is used to track all the state relevant to a single 687 // module. Previous to Terraform 0.3, all state belonged to the "root" 688 // module. 689 type ModuleState struct { 690 // Path is the import path from the root module. Modules imports are 691 // always disjoint, so the path represents amodule tree 692 Path []string `json:"path"` 693 694 // Outputs declared by the module and maintained for each module 695 // even though only the root module technically needs to be kept. 696 // This allows operators to inspect values at the boundaries. 697 Outputs map[string]*OutputState `json:"outputs"` 698 699 // Resources is a mapping of the logically named resource to 700 // the state of the resource. Each resource may actually have 701 // N instances underneath, although a user only needs to think 702 // about the 1:1 case. 703 Resources map[string]*ResourceState `json:"resources"` 704 705 // Dependencies are a list of things that this module relies on 706 // existing to remain intact. For example: an module may depend 707 // on a VPC ID given by an aws_vpc resource. 708 // 709 // Terraform uses this information to build valid destruction 710 // orders and to warn the user if they're destroying a module that 711 // another resource depends on. 712 // 713 // Things can be put into this list that may not be managed by 714 // Terraform. If Terraform doesn't find a matching ID in the 715 // overall state, then it assumes it isn't managed and doesn't 716 // worry about it. 717 Dependencies []string `json:"depends_on,omitempty"` 718 } 719 720 // Equal tests whether one module state is equal to another. 721 func (m *ModuleState) Equal(other *ModuleState) bool { 722 // Paths must be equal 723 if !reflect.DeepEqual(m.Path, other.Path) { 724 return false 725 } 726 727 // Outputs must be equal 728 if len(m.Outputs) != len(other.Outputs) { 729 return false 730 } 731 for k, v := range m.Outputs { 732 if !other.Outputs[k].Equal(v) { 733 return false 734 } 735 } 736 737 // Dependencies must be equal. This sorts these in place but 738 // this shouldn't cause any problems. 739 sort.Strings(m.Dependencies) 740 sort.Strings(other.Dependencies) 741 if len(m.Dependencies) != len(other.Dependencies) { 742 return false 743 } 744 for i, d := range m.Dependencies { 745 if other.Dependencies[i] != d { 746 return false 747 } 748 } 749 750 // Resources must be equal 751 if len(m.Resources) != len(other.Resources) { 752 return false 753 } 754 for k, r := range m.Resources { 755 otherR, ok := other.Resources[k] 756 if !ok { 757 return false 758 } 759 760 if !r.Equal(otherR) { 761 return false 762 } 763 } 764 765 return true 766 } 767 768 // IsRoot says whether or not this module diff is for the root module. 769 func (m *ModuleState) IsRoot() bool { 770 return reflect.DeepEqual(m.Path, rootModulePath) 771 } 772 773 // Orphans returns a list of keys of resources that are in the State 774 // but aren't present in the configuration itself. Hence, these keys 775 // represent the state of resources that are orphans. 776 func (m *ModuleState) Orphans(c *config.Config) []string { 777 keys := make(map[string]struct{}) 778 for k, _ := range m.Resources { 779 keys[k] = struct{}{} 780 } 781 782 if c != nil { 783 for _, r := range c.Resources { 784 delete(keys, r.Id()) 785 786 for k, _ := range keys { 787 if strings.HasPrefix(k, r.Id()+".") { 788 delete(keys, k) 789 } 790 } 791 } 792 } 793 794 result := make([]string, 0, len(keys)) 795 for k, _ := range keys { 796 result = append(result, k) 797 } 798 799 return result 800 } 801 802 // View returns a view with the given resource prefix. 803 func (m *ModuleState) View(id string) *ModuleState { 804 if m == nil { 805 return m 806 } 807 808 r := m.deepcopy() 809 for k, _ := range r.Resources { 810 if id == k || strings.HasPrefix(k, id+".") { 811 continue 812 } 813 814 delete(r.Resources, k) 815 } 816 817 return r 818 } 819 820 func (m *ModuleState) init() { 821 if m.Outputs == nil { 822 m.Outputs = make(map[string]*OutputState) 823 } 824 if m.Resources == nil { 825 m.Resources = make(map[string]*ResourceState) 826 } 827 } 828 829 func (m *ModuleState) deepcopy() *ModuleState { 830 if m == nil { 831 return nil 832 } 833 n := &ModuleState{ 834 Path: make([]string, len(m.Path)), 835 Outputs: make(map[string]*OutputState, len(m.Outputs)), 836 Resources: make(map[string]*ResourceState, len(m.Resources)), 837 Dependencies: make([]string, len(m.Dependencies)), 838 } 839 copy(n.Path, m.Path) 840 copy(n.Dependencies, m.Dependencies) 841 for k, v := range m.Outputs { 842 n.Outputs[k] = v.deepcopy() 843 } 844 for k, v := range m.Resources { 845 n.Resources[k] = v.deepcopy() 846 } 847 return n 848 } 849 850 // prune is used to remove any resources that are no longer required 851 func (m *ModuleState) prune() { 852 for k, v := range m.Resources { 853 v.prune() 854 855 if (v.Primary == nil || v.Primary.ID == "") && len(v.Deposed) == 0 { 856 delete(m.Resources, k) 857 } 858 } 859 860 for k, v := range m.Outputs { 861 if v.Value == config.UnknownVariableValue { 862 delete(m.Outputs, k) 863 } 864 } 865 } 866 867 func (m *ModuleState) sort() { 868 for _, v := range m.Resources { 869 v.sort() 870 } 871 } 872 873 func (m *ModuleState) GoString() string { 874 return fmt.Sprintf("*%#v", *m) 875 } 876 877 func (m *ModuleState) String() string { 878 var buf bytes.Buffer 879 880 if len(m.Resources) == 0 { 881 buf.WriteString("<no state>") 882 } 883 884 names := make([]string, 0, len(m.Resources)) 885 for name, _ := range m.Resources { 886 names = append(names, name) 887 } 888 sort.Strings(names) 889 890 for _, k := range names { 891 rs := m.Resources[k] 892 var id string 893 if rs.Primary != nil { 894 id = rs.Primary.ID 895 } 896 if id == "" { 897 id = "<not created>" 898 } 899 900 taintStr := "" 901 if rs.Primary.Tainted { 902 taintStr = " (tainted)" 903 } 904 905 deposedStr := "" 906 if len(rs.Deposed) > 0 { 907 deposedStr = fmt.Sprintf(" (%d deposed)", len(rs.Deposed)) 908 } 909 910 buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr)) 911 buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) 912 if rs.Provider != "" { 913 buf.WriteString(fmt.Sprintf(" provider = %s\n", rs.Provider)) 914 } 915 916 var attributes map[string]string 917 if rs.Primary != nil { 918 attributes = rs.Primary.Attributes 919 } 920 attrKeys := make([]string, 0, len(attributes)) 921 for ak, _ := range attributes { 922 if ak == "id" { 923 continue 924 } 925 926 attrKeys = append(attrKeys, ak) 927 } 928 sort.Strings(attrKeys) 929 930 for _, ak := range attrKeys { 931 av := attributes[ak] 932 buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) 933 } 934 935 for idx, t := range rs.Deposed { 936 taintStr := "" 937 if t.Tainted { 938 taintStr = " (tainted)" 939 } 940 buf.WriteString(fmt.Sprintf(" Deposed ID %d = %s%s\n", idx+1, t.ID, taintStr)) 941 } 942 943 if len(rs.Dependencies) > 0 { 944 buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) 945 for _, dep := range rs.Dependencies { 946 buf.WriteString(fmt.Sprintf(" %s\n", dep)) 947 } 948 } 949 } 950 951 if len(m.Outputs) > 0 { 952 buf.WriteString("\nOutputs:\n\n") 953 954 ks := make([]string, 0, len(m.Outputs)) 955 for k, _ := range m.Outputs { 956 ks = append(ks, k) 957 } 958 sort.Strings(ks) 959 960 for _, k := range ks { 961 v := m.Outputs[k] 962 switch vTyped := v.Value.(type) { 963 case string: 964 buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped)) 965 case []interface{}: 966 buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped)) 967 case map[string]interface{}: 968 var mapKeys []string 969 for key, _ := range vTyped { 970 mapKeys = append(mapKeys, key) 971 } 972 sort.Strings(mapKeys) 973 974 var mapBuf bytes.Buffer 975 mapBuf.WriteString("{") 976 for _, key := range mapKeys { 977 mapBuf.WriteString(fmt.Sprintf("%s:%s ", key, vTyped[key])) 978 } 979 mapBuf.WriteString("}") 980 981 buf.WriteString(fmt.Sprintf("%s = %s\n", k, mapBuf.String())) 982 } 983 } 984 } 985 986 return buf.String() 987 } 988 989 // ResourceStateKey is a structured representation of the key used for the 990 // ModuleState.Resources mapping 991 type ResourceStateKey struct { 992 Name string 993 Type string 994 Mode config.ResourceMode 995 Index int 996 } 997 998 // Equal determines whether two ResourceStateKeys are the same 999 func (rsk *ResourceStateKey) Equal(other *ResourceStateKey) bool { 1000 if rsk == nil || other == nil { 1001 return false 1002 } 1003 if rsk.Mode != other.Mode { 1004 return false 1005 } 1006 if rsk.Type != other.Type { 1007 return false 1008 } 1009 if rsk.Name != other.Name { 1010 return false 1011 } 1012 if rsk.Index != other.Index { 1013 return false 1014 } 1015 return true 1016 } 1017 1018 func (rsk *ResourceStateKey) String() string { 1019 if rsk == nil { 1020 return "" 1021 } 1022 var prefix string 1023 switch rsk.Mode { 1024 case config.ManagedResourceMode: 1025 prefix = "" 1026 case config.DataResourceMode: 1027 prefix = "data." 1028 default: 1029 panic(fmt.Errorf("unknown resource mode %s", rsk.Mode)) 1030 } 1031 if rsk.Index == -1 { 1032 return fmt.Sprintf("%s%s.%s", prefix, rsk.Type, rsk.Name) 1033 } 1034 return fmt.Sprintf("%s%s.%s.%d", prefix, rsk.Type, rsk.Name, rsk.Index) 1035 } 1036 1037 // ParseResourceStateKey accepts a key in the format used by 1038 // ModuleState.Resources and returns a resource name and resource index. In the 1039 // state, a resource has the format "type.name.index" or "type.name". In the 1040 // latter case, the index is returned as -1. 1041 func ParseResourceStateKey(k string) (*ResourceStateKey, error) { 1042 parts := strings.Split(k, ".") 1043 mode := config.ManagedResourceMode 1044 if len(parts) > 0 && parts[0] == "data" { 1045 mode = config.DataResourceMode 1046 // Don't need the constant "data" prefix for parsing 1047 // now that we've figured out the mode. 1048 parts = parts[1:] 1049 } 1050 if len(parts) < 2 || len(parts) > 3 { 1051 return nil, fmt.Errorf("Malformed resource state key: %s", k) 1052 } 1053 rsk := &ResourceStateKey{ 1054 Mode: mode, 1055 Type: parts[0], 1056 Name: parts[1], 1057 Index: -1, 1058 } 1059 if len(parts) == 3 { 1060 index, err := strconv.Atoi(parts[2]) 1061 if err != nil { 1062 return nil, fmt.Errorf("Malformed resource state key index: %s", k) 1063 } 1064 rsk.Index = index 1065 } 1066 return rsk, nil 1067 } 1068 1069 // ResourceState holds the state of a resource that is used so that 1070 // a provider can find and manage an existing resource as well as for 1071 // storing attributes that are used to populate variables of child 1072 // resources. 1073 // 1074 // Attributes has attributes about the created resource that are 1075 // queryable in interpolation: "${type.id.attr}" 1076 // 1077 // Extra is just extra data that a provider can return that we store 1078 // for later, but is not exposed in any way to the user. 1079 // 1080 type ResourceState struct { 1081 // This is filled in and managed by Terraform, and is the resource 1082 // type itself such as "mycloud_instance". If a resource provider sets 1083 // this value, it won't be persisted. 1084 Type string `json:"type"` 1085 1086 // Dependencies are a list of things that this resource relies on 1087 // existing to remain intact. For example: an AWS instance might 1088 // depend on a subnet (which itself might depend on a VPC, and so 1089 // on). 1090 // 1091 // Terraform uses this information to build valid destruction 1092 // orders and to warn the user if they're destroying a resource that 1093 // another resource depends on. 1094 // 1095 // Things can be put into this list that may not be managed by 1096 // Terraform. If Terraform doesn't find a matching ID in the 1097 // overall state, then it assumes it isn't managed and doesn't 1098 // worry about it. 1099 Dependencies []string `json:"depends_on,omitempty"` 1100 1101 // Primary is the current active instance for this resource. 1102 // It can be replaced but only after a successful creation. 1103 // This is the instances on which providers will act. 1104 Primary *InstanceState `json:"primary"` 1105 1106 // Deposed is used in the mechanics of CreateBeforeDestroy: the existing 1107 // Primary is Deposed to get it out of the way for the replacement Primary to 1108 // be created by Apply. If the replacement Primary creates successfully, the 1109 // Deposed instance is cleaned up. 1110 // 1111 // If there were problems creating the replacement Primary, the Deposed 1112 // instance and the (now tainted) replacement Primary will be swapped so the 1113 // tainted replacement will be cleaned up instead. 1114 // 1115 // An instance will remain in the Deposed list until it is successfully 1116 // destroyed and purged. 1117 Deposed []*InstanceState `json:"deposed,omitempty"` 1118 1119 // Provider is used when a resource is connected to a provider with an alias. 1120 // If this string is empty, the resource is connected to the default provider, 1121 // e.g. "aws_instance" goes with the "aws" provider. 1122 // If the resource block contained a "provider" key, that value will be set here. 1123 Provider string `json:"provider,omitempty"` 1124 } 1125 1126 // Equal tests whether two ResourceStates are equal. 1127 func (s *ResourceState) Equal(other *ResourceState) bool { 1128 if s.Type != other.Type { 1129 return false 1130 } 1131 1132 if s.Provider != other.Provider { 1133 return false 1134 } 1135 1136 // Dependencies must be equal 1137 sort.Strings(s.Dependencies) 1138 sort.Strings(other.Dependencies) 1139 if len(s.Dependencies) != len(other.Dependencies) { 1140 return false 1141 } 1142 for i, d := range s.Dependencies { 1143 if other.Dependencies[i] != d { 1144 return false 1145 } 1146 } 1147 1148 // States must be equal 1149 if !s.Primary.Equal(other.Primary) { 1150 return false 1151 } 1152 1153 return true 1154 } 1155 1156 // Taint marks a resource as tainted. 1157 func (r *ResourceState) Taint() { 1158 if r.Primary != nil { 1159 r.Primary.Tainted = true 1160 } 1161 } 1162 1163 // Untaint unmarks a resource as tainted. 1164 func (r *ResourceState) Untaint() { 1165 if r.Primary != nil { 1166 r.Primary.Tainted = false 1167 } 1168 } 1169 1170 func (r *ResourceState) init() { 1171 if r.Primary == nil { 1172 r.Primary = &InstanceState{} 1173 } 1174 r.Primary.init() 1175 } 1176 1177 func (r *ResourceState) deepcopy() *ResourceState { 1178 copy, err := copystructure.Copy(r) 1179 if err != nil { 1180 panic(err) 1181 } 1182 1183 return copy.(*ResourceState) 1184 } 1185 1186 // prune is used to remove any instances that are no longer required 1187 func (r *ResourceState) prune() { 1188 n := len(r.Deposed) 1189 for i := 0; i < n; i++ { 1190 inst := r.Deposed[i] 1191 if inst == nil || inst.ID == "" { 1192 copy(r.Deposed[i:], r.Deposed[i+1:]) 1193 r.Deposed[n-1] = nil 1194 n-- 1195 i-- 1196 } 1197 } 1198 1199 r.Deposed = r.Deposed[:n] 1200 } 1201 1202 func (r *ResourceState) sort() { 1203 sort.Strings(r.Dependencies) 1204 } 1205 1206 func (s *ResourceState) GoString() string { 1207 return fmt.Sprintf("*%#v", *s) 1208 } 1209 1210 func (s *ResourceState) String() string { 1211 var buf bytes.Buffer 1212 buf.WriteString(fmt.Sprintf("Type = %s", s.Type)) 1213 return buf.String() 1214 } 1215 1216 // InstanceState is used to track the unique state information belonging 1217 // to a given instance. 1218 type InstanceState struct { 1219 // A unique ID for this resource. This is opaque to Terraform 1220 // and is only meant as a lookup mechanism for the providers. 1221 ID string `json:"id"` 1222 1223 // Attributes are basic information about the resource. Any keys here 1224 // are accessible in variable format within Terraform configurations: 1225 // ${resourcetype.name.attribute}. 1226 Attributes map[string]string `json:"attributes,omitempty"` 1227 1228 // Ephemeral is used to store any state associated with this instance 1229 // that is necessary for the Terraform run to complete, but is not 1230 // persisted to a state file. 1231 Ephemeral EphemeralState `json:"-"` 1232 1233 // Meta is a simple K/V map that is persisted to the State but otherwise 1234 // ignored by Terraform core. It's meant to be used for accounting by 1235 // external client code. 1236 Meta map[string]string `json:"meta,omitempty"` 1237 1238 // Tainted is used to mark a resource for recreation. 1239 Tainted bool `json:"tainted,omitempty"` 1240 } 1241 1242 func (i *InstanceState) init() { 1243 if i.Attributes == nil { 1244 i.Attributes = make(map[string]string) 1245 } 1246 if i.Meta == nil { 1247 i.Meta = make(map[string]string) 1248 } 1249 i.Ephemeral.init() 1250 } 1251 1252 func (i *InstanceState) DeepCopy() *InstanceState { 1253 copy, err := copystructure.Copy(i) 1254 if err != nil { 1255 panic(err) 1256 } 1257 1258 return copy.(*InstanceState) 1259 } 1260 1261 func (s *InstanceState) Empty() bool { 1262 return s == nil || s.ID == "" 1263 } 1264 1265 func (s *InstanceState) Equal(other *InstanceState) bool { 1266 // Short circuit some nil checks 1267 if s == nil || other == nil { 1268 return s == other 1269 } 1270 1271 // IDs must be equal 1272 if s.ID != other.ID { 1273 return false 1274 } 1275 1276 // Attributes must be equal 1277 if len(s.Attributes) != len(other.Attributes) { 1278 return false 1279 } 1280 for k, v := range s.Attributes { 1281 otherV, ok := other.Attributes[k] 1282 if !ok { 1283 return false 1284 } 1285 1286 if v != otherV { 1287 return false 1288 } 1289 } 1290 1291 // Meta must be equal 1292 if len(s.Meta) != len(other.Meta) { 1293 return false 1294 } 1295 for k, v := range s.Meta { 1296 otherV, ok := other.Meta[k] 1297 if !ok { 1298 return false 1299 } 1300 1301 if v != otherV { 1302 return false 1303 } 1304 } 1305 1306 if s.Tainted != other.Tainted { 1307 return false 1308 } 1309 1310 return true 1311 } 1312 1313 // MergeDiff takes a ResourceDiff and merges the attributes into 1314 // this resource state in order to generate a new state. This new 1315 // state can be used to provide updated attribute lookups for 1316 // variable interpolation. 1317 // 1318 // If the diff attribute requires computing the value, and hence 1319 // won't be available until apply, the value is replaced with the 1320 // computeID. 1321 func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { 1322 result := s.DeepCopy() 1323 if result == nil { 1324 result = new(InstanceState) 1325 } 1326 result.init() 1327 1328 if s != nil { 1329 for k, v := range s.Attributes { 1330 result.Attributes[k] = v 1331 } 1332 } 1333 if d != nil { 1334 for k, diff := range d.Attributes { 1335 if diff.NewRemoved { 1336 delete(result.Attributes, k) 1337 continue 1338 } 1339 if diff.NewComputed { 1340 result.Attributes[k] = config.UnknownVariableValue 1341 continue 1342 } 1343 1344 result.Attributes[k] = diff.New 1345 } 1346 } 1347 1348 return result 1349 } 1350 1351 func (i *InstanceState) GoString() string { 1352 return fmt.Sprintf("*%#v", *i) 1353 } 1354 1355 func (i *InstanceState) String() string { 1356 var buf bytes.Buffer 1357 1358 if i == nil || i.ID == "" { 1359 return "<not created>" 1360 } 1361 1362 buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID)) 1363 1364 attributes := i.Attributes 1365 attrKeys := make([]string, 0, len(attributes)) 1366 for ak, _ := range attributes { 1367 if ak == "id" { 1368 continue 1369 } 1370 1371 attrKeys = append(attrKeys, ak) 1372 } 1373 sort.Strings(attrKeys) 1374 1375 for _, ak := range attrKeys { 1376 av := attributes[ak] 1377 buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av)) 1378 } 1379 1380 buf.WriteString(fmt.Sprintf("Tainted = %t\n", i.Tainted)) 1381 1382 return buf.String() 1383 } 1384 1385 // EphemeralState is used for transient state that is only kept in-memory 1386 type EphemeralState struct { 1387 // ConnInfo is used for the providers to export information which is 1388 // used to connect to the resource for provisioning. For example, 1389 // this could contain SSH or WinRM credentials. 1390 ConnInfo map[string]string `json:"-"` 1391 1392 // Type is used to specify the resource type for this instance. This is only 1393 // required for import operations (as documented). If the documentation 1394 // doesn't state that you need to set this, then don't worry about 1395 // setting it. 1396 Type string `json:"-"` 1397 } 1398 1399 func (e *EphemeralState) init() { 1400 if e.ConnInfo == nil { 1401 e.ConnInfo = make(map[string]string) 1402 } 1403 } 1404 1405 func (e *EphemeralState) DeepCopy() *EphemeralState { 1406 copy, err := copystructure.Copy(e) 1407 if err != nil { 1408 panic(err) 1409 } 1410 1411 return copy.(*EphemeralState) 1412 } 1413 1414 type jsonStateVersionIdentifier struct { 1415 Version int `json:"version"` 1416 } 1417 1418 // Check if this is a V0 format - the magic bytes at the start of the file 1419 // should be "tfstate" if so. We no longer support upgrading this type of 1420 // state but return an error message explaining to a user how they can 1421 // upgrade via the 0.6.x series. 1422 func testForV0State(buf *bufio.Reader) error { 1423 start, err := buf.Peek(len("tfstate")) 1424 if err != nil { 1425 return fmt.Errorf("Failed to check for magic bytes: %v", err) 1426 } 1427 if string(start) == "tfstate" { 1428 return fmt.Errorf("Terraform 0.7 no longer supports upgrading the binary state\n" + 1429 "format which was used prior to Terraform 0.3. Please upgrade\n" + 1430 "this state file using Terraform 0.6.16 prior to using it with\n" + 1431 "Terraform 0.7.") 1432 } 1433 1434 return nil 1435 } 1436 1437 // ReadState reads a state structure out of a reader in the format that 1438 // was written by WriteState. 1439 func ReadState(src io.Reader) (*State, error) { 1440 buf := bufio.NewReader(src) 1441 1442 if err := testForV0State(buf); err != nil { 1443 return nil, err 1444 } 1445 1446 // If we are JSON we buffer the whole thing in memory so we can read it twice. 1447 // This is suboptimal, but will work for now. 1448 jsonBytes, err := ioutil.ReadAll(buf) 1449 if err != nil { 1450 return nil, fmt.Errorf("Reading state file failed: %v", err) 1451 } 1452 1453 versionIdentifier := &jsonStateVersionIdentifier{} 1454 if err := json.Unmarshal(jsonBytes, versionIdentifier); err != nil { 1455 return nil, fmt.Errorf("Decoding state file version failed: %v", err) 1456 } 1457 1458 switch versionIdentifier.Version { 1459 case 0: 1460 return nil, fmt.Errorf("State version 0 is not supported as JSON.") 1461 case 1: 1462 v1State, err := ReadStateV1(jsonBytes) 1463 if err != nil { 1464 return nil, err 1465 } 1466 1467 v2State, err := upgradeStateV1ToV2(v1State) 1468 if err != nil { 1469 return nil, err 1470 } 1471 1472 v3State, err := upgradeStateV2ToV3(v2State) 1473 if err != nil { 1474 return nil, err 1475 } 1476 1477 // increment the Serial whenever we upgrade state 1478 v3State.Serial++ 1479 return v3State, nil 1480 case 2: 1481 v2State, err := ReadStateV2(jsonBytes) 1482 if err != nil { 1483 return nil, err 1484 } 1485 v3State, err := upgradeStateV2ToV3(v2State) 1486 if err != nil { 1487 return nil, err 1488 } 1489 1490 v3State.Serial++ 1491 return v3State, nil 1492 case 3: 1493 v3State, err := ReadStateV3(jsonBytes) 1494 if err != nil { 1495 return nil, err 1496 } 1497 return v3State, nil 1498 default: 1499 return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", 1500 SemVersion.String(), versionIdentifier.Version) 1501 } 1502 } 1503 1504 func ReadStateV1(jsonBytes []byte) (*stateV1, error) { 1505 v1State := &stateV1{} 1506 if err := json.Unmarshal(jsonBytes, v1State); err != nil { 1507 return nil, fmt.Errorf("Decoding state file failed: %v", err) 1508 } 1509 1510 if v1State.Version != 1 { 1511 return nil, fmt.Errorf("Decoded state version did not match the decoder selection: "+ 1512 "read %d, expected 1", v1State.Version) 1513 } 1514 1515 return v1State, nil 1516 } 1517 1518 func ReadStateV2(jsonBytes []byte) (*State, error) { 1519 state := &State{} 1520 if err := json.Unmarshal(jsonBytes, state); err != nil { 1521 return nil, fmt.Errorf("Decoding state file failed: %v", err) 1522 } 1523 1524 // Check the version, this to ensure we don't read a future 1525 // version that we don't understand 1526 if state.Version > StateVersion { 1527 return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", 1528 SemVersion.String(), state.Version) 1529 } 1530 1531 // Make sure the version is semantic 1532 if state.TFVersion != "" { 1533 if _, err := version.NewVersion(state.TFVersion); err != nil { 1534 return nil, fmt.Errorf( 1535 "State contains invalid version: %s\n\n"+ 1536 "Terraform validates the version format prior to writing it. This\n"+ 1537 "means that this is invalid of the state becoming corrupted through\n"+ 1538 "some external means. Please manually modify the Terraform version\n"+ 1539 "field to be a proper semantic version.", 1540 state.TFVersion) 1541 } 1542 } 1543 1544 // Sort it 1545 state.sort() 1546 1547 return state, nil 1548 } 1549 1550 func ReadStateV3(jsonBytes []byte) (*State, error) { 1551 state := &State{} 1552 if err := json.Unmarshal(jsonBytes, state); err != nil { 1553 return nil, fmt.Errorf("Decoding state file failed: %v", err) 1554 } 1555 1556 // Check the version, this to ensure we don't read a future 1557 // version that we don't understand 1558 if state.Version > StateVersion { 1559 return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.", 1560 SemVersion.String(), state.Version) 1561 } 1562 1563 // Make sure the version is semantic 1564 if state.TFVersion != "" { 1565 if _, err := version.NewVersion(state.TFVersion); err != nil { 1566 return nil, fmt.Errorf( 1567 "State contains invalid version: %s\n\n"+ 1568 "Terraform validates the version format prior to writing it. This\n"+ 1569 "means that this is invalid of the state becoming corrupted through\n"+ 1570 "some external means. Please manually modify the Terraform version\n"+ 1571 "field to be a proper semantic version.", 1572 state.TFVersion) 1573 } 1574 } 1575 1576 // Sort it 1577 state.sort() 1578 1579 return state, nil 1580 } 1581 1582 // WriteState writes a state somewhere in a binary format. 1583 func WriteState(d *State, dst io.Writer) error { 1584 // Make sure it is sorted 1585 d.sort() 1586 1587 // Ensure the version is set 1588 d.Version = StateVersion 1589 1590 // If the TFVersion is set, verify it. We used to just set the version 1591 // here, but this isn't safe since it changes the MD5 sum on some remote 1592 // state storage backends such as Atlas. We now leave it be if needed. 1593 if d.TFVersion != "" { 1594 if _, err := version.NewVersion(d.TFVersion); err != nil { 1595 return fmt.Errorf( 1596 "Error writing state, invalid version: %s\n\n"+ 1597 "The Terraform version when writing the state must be a semantic\n"+ 1598 "version.", 1599 d.TFVersion) 1600 } 1601 } 1602 1603 // Encode the data in a human-friendly way 1604 data, err := json.MarshalIndent(d, "", " ") 1605 if err != nil { 1606 return fmt.Errorf("Failed to encode state: %s", err) 1607 } 1608 1609 // We append a newline to the data because MarshalIndent doesn't 1610 data = append(data, '\n') 1611 1612 // Write the data out to the dst 1613 if _, err := io.Copy(dst, bytes.NewReader(data)); err != nil { 1614 return fmt.Errorf("Failed to write state: %v", err) 1615 } 1616 1617 return nil 1618 } 1619 1620 // moduleStateSort implements sort.Interface to sort module states 1621 type moduleStateSort []*ModuleState 1622 1623 func (s moduleStateSort) Len() int { 1624 return len(s) 1625 } 1626 1627 func (s moduleStateSort) Less(i, j int) bool { 1628 a := s[i] 1629 b := s[j] 1630 1631 // If the lengths are different, then the shorter one always wins 1632 if len(a.Path) != len(b.Path) { 1633 return len(a.Path) < len(b.Path) 1634 } 1635 1636 // Otherwise, compare lexically 1637 return strings.Join(a.Path, ".") < strings.Join(b.Path, ".") 1638 } 1639 1640 func (s moduleStateSort) Swap(i, j int) { 1641 s[i], s[j] = s[j], s[i] 1642 }