From 5dc37bafe6884209f6df198b1fc2b909e05cf341 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 15:31:17 -0700 Subject: [PATCH 01/85] Adding the new state structures --- terraform/state.go | 351 +++++++++++------------------------------- terraform/state_v1.go | 279 +++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+), 258 deletions(-) create mode 100644 terraform/state_v1.go diff --git a/terraform/state.go b/terraform/state.go index 2e45a661f..281893e24 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1,181 +1,121 @@ package terraform import ( - "bytes" "encoding/gob" "errors" "fmt" "io" - "sort" - "sync" - - "github.com/hashicorp/terraform/config" ) // State keeps track of a snapshot state-of-the-world that Terraform // can use to keep track of what real world resources it is actually -// managing. +// managing. This is the latest format as of Terraform 0.3 type State struct { - Outputs map[string]string - Resources map[string]*ResourceState - Tainted map[string]struct{} + // Version is the protocol version. Currently only "1". + Version int `json:"version"` - once sync.Once + // Serial is incremented on any operation that modifies + // the State file. It is used to detect potentially conflicting + // updates. + Serial int64 `json:"serial"` + + // Modules contains all the modules in a breadth-first order + Modules []*ModuleState `json:"modules"` } -func (s *State) init() { - s.once.Do(func() { - if s.Resources == nil { - s.Resources = make(map[string]*ResourceState) - } +// ModuleState is used to track all the state relevant to a single +// module. Previous to Terraform 0.3, all state belonged to the "root" +// module. +type ModuleState struct { + // Path is the import path from the root module. Modules imports are + // always disjoint, so the path represents amodule tree + Path []string `json:"path"` - if s.Tainted == nil { - s.Tainted = make(map[string]struct{}) - } - }) + // Outputs declared by the module and maintained for each module + // even though only the root module technically needs to be kept. + // This allows operators to inspect values at the boundaries. + Outputs map[string]string `json:"outputs"` + + // Resources is a mapping of the logically named resource to + // the state of the resource. Each resource may actually have + // N instances underneath, although a user only needs to think + // about the 1:1 case. + Resources map[string]*ResourceState `json:"resources"` } -func (s *State) deepcopy() *State { - result := new(State) - result.init() - if s != nil { - for k, v := range s.Resources { - result.Resources[k] = v - } - for k, v := range s.Tainted { - result.Tainted[k] = v - } - } +// ResourceState holds the state of a resource that is used so that +// a provider can find and manage an existing resource as well as for +// storing attributes that are used to populate variables of child +// resources. +// +// Attributes has attributes about the created resource that are +// queryable in interpolation: "${type.id.attr}" +// +// Extra is just extra data that a provider can return that we store +// for later, but is not exposed in any way to the user. +// +type ResourceState struct { + // This is filled in and managed by Terraform, and is the resource + // type itself such as "mycloud_instance". If a resource provider sets + // this value, it won't be persisted. + Type string `json:"type"` - return result + // Dependencies are a list of things that this resource relies on + // existing to remain intact. For example: an AWS instance might + // depend on a subnet (which itself might depend on a VPC, and so + // on). + // + // Terraform uses this information to build valid destruction + // orders and to warn the user if they're destroying a resource that + // another resource depends on. + // + // Things can be put into this list that may not be managed by + // Terraform. If Terraform doesn't find a matching ID in the + // overall state, then it assumes it isn't managed and doesn't + // worry about it. + Dependencies []string `json:"depends_on,omitempty"` + + // Instances is used to track all of the underlying instances + // have been created as part of this logical resource. In the + // standard case, there is only a single underlying instance. + // However, in pathological cases, it is possible for the number + // of instances to accumulate. The first instance in the list is + // the "primary" and the others should be removed on subsequent + // apply operations. + Instances []*InstanceState `json:"instances"` } -// prune is a helper that removes any empty IDs from the state -// and cleans it up in general. -func (s *State) prune() { - for k, v := range s.Resources { - if v.ID == "" { - delete(s.Resources, k) - } - } +// InstanceState is used to track the unique state information belonging +// to a given instance. +type InstanceState struct { + // A unique ID for this resource. This is opaque to Terraform + // and is only meant as a lookup mechanism for the providers. + ID string `json:"id"` + + // Tainted is used to mark a resource as existing but being in + // an unknown or errored state. Hence, it is 'tainted' and should + // be destroyed and replaced on the next fun. + Tainted bool `json:"tainted,omitempty"` + + // Attributes are basic information about the resource. Any keys here + // are accessible in variable format within Terraform configurations: + // ${resourcetype.name.attribute}. + Attributes map[string]string `json:"attributes,omitempty"` + + // Ephemeral is used to store any state associated with this instance + // that is necessary for the Terraform run to complete, but is not + // persisted to a state file. + Ephemeral EphemeralState `json:"-"` } -// Orphans returns a list of keys of resources that are in the State -// but aren't present in the configuration itself. Hence, these keys -// represent the state of resources that are orphans. -func (s *State) Orphans(c *config.Config) []string { - keys := make(map[string]struct{}) - for k, _ := range s.Resources { - keys[k] = struct{}{} - } - - for _, r := range c.Resources { - delete(keys, r.Id()) - - // Mark all the counts as not orphans. - for i := 0; i < r.Count; i++ { - delete(keys, fmt.Sprintf("%s.%d", r.Id(), i)) - } - } - - result := make([]string, 0, len(keys)) - for k, _ := range keys { - result = append(result, k) - } - - return result +// EphemeralState is used for transient state that is only kept in-memory +type EphemeralState struct { + // ConnInfo is used for the providers to export information which is + // used to connect to the resource for provisioning. For example, + // this could contain SSH or WinRM credentials. + ConnInfo map[string]string `json:"-"` } -func (s *State) String() string { - if len(s.Resources) == 0 { - return "" - } - - var buf bytes.Buffer - - names := make([]string, 0, len(s.Resources)) - for name, _ := range s.Resources { - names = append(names, name) - } - sort.Strings(names) - - for _, k := range names { - rs := s.Resources[k] - id := rs.ID - if id == "" { - id = "" - } - - taintStr := "" - if _, ok := s.Tainted[k]; ok { - taintStr = " (tainted)" - } - - buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) - buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) - - attrKeys := make([]string, 0, len(rs.Attributes)) - for ak, _ := range rs.Attributes { - if ak == "id" { - continue - } - - attrKeys = append(attrKeys, ak) - } - sort.Strings(attrKeys) - - for _, ak := range attrKeys { - av := rs.Attributes[ak] - buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) - } - - if len(rs.Dependencies) > 0 { - buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) - for _, dep := range rs.Dependencies { - buf.WriteString(fmt.Sprintf(" %s\n", dep.ID)) - } - } - } - - if len(s.Outputs) > 0 { - buf.WriteString("\nOutputs:\n\n") - - ks := make([]string, 0, len(s.Outputs)) - for k, _ := range s.Outputs { - ks = append(ks, k) - } - sort.Strings(ks) - - for _, k := range ks { - v := s.Outputs[k] - buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) - } - } - - return buf.String() -} - -// sensitiveState is used to store sensitive state information -// that should not be serialized. This is only used temporarily -// and is restored into the state. -type sensitiveState struct { - ConnInfo map[string]map[string]string - - once sync.Once -} - -func (s *sensitiveState) init() { - s.once.Do(func() { - s.ConnInfo = make(map[string]map[string]string) - }) -} - -// The format byte is prefixed into the state file format so that we have -// the ability in the future to change the file format if we want for any -// reason. -const stateFormatMagic = "tfstate" -const stateFormatVersion byte = 1 - // ReadState reads a state structure out of a reader in the format that // was written by WriteState. func ReadState(src io.Reader) (*State, error) { @@ -258,108 +198,3 @@ func WriteState(d *State, dst io.Writer) error { return err } - -// ResourceState holds the state of a resource that is used so that -// a provider can find and manage an existing resource as well as for -// storing attributes that are uesd to populate variables of child -// resources. -// -// Attributes has attributes about the created resource that are -// queryable in interpolation: "${type.id.attr}" -// -// Extra is just extra data that a provider can return that we store -// for later, but is not exposed in any way to the user. -type ResourceState struct { - // This is filled in and managed by Terraform, and is the resource - // type itself such as "mycloud_instance". If a resource provider sets - // this value, it won't be persisted. - Type string - - // The attributes below are all meant to be filled in by the - // resource providers themselves. Documentation for each are above - // each element. - - // A unique ID for this resource. This is opaque to Terraform - // and is only meant as a lookup mechanism for the providers. - ID string - - // Attributes are basic information about the resource. Any keys here - // are accessible in variable format within Terraform configurations: - // ${resourcetype.name.attribute}. - Attributes map[string]string - - // ConnInfo is used for the providers to export information which is - // used to connect to the resource for provisioning. For example, - // this could contain SSH or WinRM credentials. - ConnInfo map[string]string - - // Extra information that the provider can store about a resource. - // This data is opaque, never shown to the user, and is sent back to - // the provider as-is for whatever purpose appropriate. - Extra map[string]interface{} - - // Dependencies are a list of things that this resource relies on - // existing to remain intact. For example: an AWS instance might - // depend on a subnet (which itself might depend on a VPC, and so - // on). - // - // Terraform uses this information to build valid destruction - // orders and to warn the user if they're destroying a resource that - // another resource depends on. - // - // Things can be put into this list that may not be managed by - // Terraform. If Terraform doesn't find a matching ID in the - // overall state, then it assumes it isn't managed and doesn't - // worry about it. - Dependencies []ResourceDependency -} - -// MergeDiff takes a ResourceDiff and merges the attributes into -// this resource state in order to generate a new state. This new -// state can be used to provide updated attribute lookups for -// variable interpolation. -// -// If the diff attribute requires computing the value, and hence -// won't be available until apply, the value is replaced with the -// computeID. -func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { - var result ResourceState - if s != nil { - result = *s - } - - result.Attributes = make(map[string]string) - if s != nil { - for k, v := range s.Attributes { - result.Attributes[k] = v - } - } - if d != nil { - for k, diff := range d.Attributes { - if diff.NewRemoved { - delete(result.Attributes, k) - continue - } - if diff.NewComputed { - result.Attributes[k] = config.UnknownVariableValue - continue - } - - result.Attributes[k] = diff.New - } - } - - return &result -} - -func (s *ResourceState) GoString() string { - return fmt.Sprintf("*%#v", *s) -} - -// ResourceDependency maps a resource to another resource that it -// depends on to remain intact and uncorrupted. -type ResourceDependency struct { - // ID of the resource that we depend on. This ID should map - // directly to another ResourceState's ID. - ID string -} diff --git a/terraform/state_v1.go b/terraform/state_v1.go new file mode 100644 index 000000000..67ae2c47c --- /dev/null +++ b/terraform/state_v1.go @@ -0,0 +1,279 @@ +package terraform + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/hashicorp/terraform/config" +) + +// StateV1 is used to represent the state of Terraform files before +// 0.3. It is automatically upgraded to a modern State representation +// on start. +type StateV1 struct { + Outputs map[string]string + Resources map[string]*ResourceState + Tainted map[string]struct{} + + once sync.Once +} + +func (s *State) init() { + s.once.Do(func() { + if s.Resources == nil { + s.Resources = make(map[string]*ResourceState) + } + + if s.Tainted == nil { + s.Tainted = make(map[string]struct{}) + } + }) +} + +func (s *State) deepcopy() *State { + result := new(State) + result.init() + if s != nil { + for k, v := range s.Resources { + result.Resources[k] = v + } + for k, v := range s.Tainted { + result.Tainted[k] = v + } + } + + return result +} + +// prune is a helper that removes any empty IDs from the state +// and cleans it up in general. +func (s *State) prune() { + for k, v := range s.Resources { + if v.ID == "" { + delete(s.Resources, k) + } + } +} + +// Orphans returns a list of keys of resources that are in the State +// but aren't present in the configuration itself. Hence, these keys +// represent the state of resources that are orphans. +func (s *State) Orphans(c *config.Config) []string { + keys := make(map[string]struct{}) + for k, _ := range s.Resources { + keys[k] = struct{}{} + } + + for _, r := range c.Resources { + delete(keys, r.Id()) + + // Mark all the counts as not orphans. + for i := 0; i < r.Count; i++ { + delete(keys, fmt.Sprintf("%s.%d", r.Id(), i)) + } + } + + result := make([]string, 0, len(keys)) + for k, _ := range keys { + result = append(result, k) + } + + return result +} + +func (s *State) String() string { + if len(s.Resources) == 0 { + return "" + } + + var buf bytes.Buffer + + names := make([]string, 0, len(s.Resources)) + for name, _ := range s.Resources { + names = append(names, name) + } + sort.Strings(names) + + for _, k := range names { + rs := s.Resources[k] + id := rs.ID + if id == "" { + id = "" + } + + taintStr := "" + if _, ok := s.Tainted[k]; ok { + taintStr = " (tainted)" + } + + buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) + buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) + + attrKeys := make([]string, 0, len(rs.Attributes)) + for ak, _ := range rs.Attributes { + if ak == "id" { + continue + } + + attrKeys = append(attrKeys, ak) + } + sort.Strings(attrKeys) + + for _, ak := range attrKeys { + av := rs.Attributes[ak] + buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) + } + + if len(rs.Dependencies) > 0 { + buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) + for _, dep := range rs.Dependencies { + buf.WriteString(fmt.Sprintf(" %s\n", dep.ID)) + } + } + } + + if len(s.Outputs) > 0 { + buf.WriteString("\nOutputs:\n\n") + + ks := make([]string, 0, len(s.Outputs)) + for k, _ := range s.Outputs { + ks = append(ks, k) + } + sort.Strings(ks) + + for _, k := range ks { + v := s.Outputs[k] + buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) + } + } + + return buf.String() +} + +// sensitiveState is used to store sensitive state information +// that should not be serialized. This is only used temporarily +// and is restored into the state. +type sensitiveState struct { + ConnInfo map[string]map[string]string + + once sync.Once +} + +func (s *sensitiveState) init() { + s.once.Do(func() { + s.ConnInfo = make(map[string]map[string]string) + }) +} + +// The format byte is prefixed into the state file format so that we have +// the ability in the future to change the file format if we want for any +// reason. +const stateFormatMagic = "tfstate" +const stateFormatVersion byte = 1 + +/// ResourceState holds the state of a resource that is used so that +// a provider can find and manage an existing resource as well as for +// storing attributes that are uesd to populate variables of child +// resources. +// +// Attributes has attributes about the created resource that are +// queryable in interpolation: "${type.id.attr}" +// +// Extra is just extra data that a provider can return that we store +// for later, but is not exposed in any way to the user. +type ResourceStateV1 struct { + // This is filled in and managed by Terraform, and is the resource + // type itself such as "mycloud_instance". If a resource provider sets + // this value, it won't be persisted. + Type string + + // The attributes below are all meant to be filled in by the + // resource providers themselves. Documentation for each are above + // each element. + + // A unique ID for this resource. This is opaque to Terraform + // and is only meant as a lookup mechanism for the providers. + ID string + + // Attributes are basic information about the resource. Any keys here + // are accessible in variable format within Terraform configurations: + // ${resourcetype.name.attribute}. + Attributes map[string]string + + // ConnInfo is used for the providers to export information which is + // used to connect to the resource for provisioning. For example, + // this could contain SSH or WinRM credentials. + ConnInfo map[string]string + + // Extra information that the provider can store about a resource. + // This data is opaque, never shown to the user, and is sent back to + // the provider as-is for whatever purpose appropriate. + Extra map[string]interface{} + + // Dependencies are a list of things that this resource relies on + // existing to remain intact. For example: an AWS instance might + // depend on a subnet (which itself might depend on a VPC, and so + // on). + // + // Terraform uses this information to build valid destruction + // orders and to warn the user if they're destroying a resource that + // another resource depends on. + // + // Things can be put into this list that may not be managed by + // Terraform. If Terraform doesn't find a matching ID in the + // overall state, then it assumes it isn't managed and doesn't + // worry about it. + Dependencies []ResourceDependency +} + +// MergeDiff takes a ResourceDiff and merges the attributes into +// this resource state in order to generate a new state. This new +// state can be used to provide updated attribute lookups for +// variable interpolation. +// +// If the diff attribute requires computing the value, and hence +// won't be available until apply, the value is replaced with the +// computeID. +func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { + var result ResourceState + if s != nil { + result = *s + } + + result.Attributes = make(map[string]string) + if s != nil { + for k, v := range s.Attributes { + result.Attributes[k] = v + } + } + if d != nil { + for k, diff := range d.Attributes { + if diff.NewRemoved { + delete(result.Attributes, k) + continue + } + if diff.NewComputed { + result.Attributes[k] = config.UnknownVariableValue + continue + } + + result.Attributes[k] = diff.New + } + } + + return &result +} + +func (s *ResourceState) GoString() string { + return fmt.Sprintf("*%#v", *s) +} + +// ResourceDependency maps a resource to another resource that it +// depends on to remain intact and uncorrupted. +type ResourceDependency struct { + // ID of the resource that we depend on. This ID should map + // directly to another ResourceState's ID. + ID string +} From 6373b2b90bbec7897cf93e955c4c4bdbc39d8769 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 16:08:01 -0700 Subject: [PATCH 02/85] Renaming to suffix V1 to old state structs --- terraform/state_v1.go | 90 +++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/terraform/state_v1.go b/terraform/state_v1.go index 67ae2c47c..d1f44c554 100644 --- a/terraform/state_v1.go +++ b/terraform/state_v1.go @@ -2,13 +2,24 @@ package terraform import ( "bytes" + "encoding/gob" + "errors" "fmt" + "io" "sort" "sync" "github.com/hashicorp/terraform/config" ) +// The format byte is prefixed into the state file format so that we have +// the ability in the future to change the file format if we want for any +// reason. +const ( + stateFormatMagic = "tfstate" + stateFormatVersion byte = 1 +) + // StateV1 is used to represent the state of Terraform files before // 0.3. It is automatically upgraded to a modern State representation // on start. @@ -20,7 +31,7 @@ type StateV1 struct { once sync.Once } -func (s *State) init() { +func (s *StateV1) init() { s.once.Do(func() { if s.Resources == nil { s.Resources = make(map[string]*ResourceState) @@ -32,7 +43,7 @@ func (s *State) init() { }) } -func (s *State) deepcopy() *State { +func (s *StateV1) deepcopy() *State { result := new(State) result.init() if s != nil { @@ -49,7 +60,7 @@ func (s *State) deepcopy() *State { // prune is a helper that removes any empty IDs from the state // and cleans it up in general. -func (s *State) prune() { +func (s *StateV1) prune() { for k, v := range s.Resources { if v.ID == "" { delete(s.Resources, k) @@ -60,7 +71,7 @@ func (s *State) prune() { // Orphans returns a list of keys of resources that are in the State // but aren't present in the configuration itself. Hence, these keys // represent the state of resources that are orphans. -func (s *State) Orphans(c *config.Config) []string { +func (s *StateV1) Orphans(c *config.Config) []string { keys := make(map[string]struct{}) for k, _ := range s.Resources { keys[k] = struct{}{} @@ -83,7 +94,7 @@ func (s *State) Orphans(c *config.Config) []string { return result } -func (s *State) String() string { +func (s *StateV1) String() string { if len(s.Resources) == 0 { return "" } @@ -152,27 +163,6 @@ func (s *State) String() string { return buf.String() } -// sensitiveState is used to store sensitive state information -// that should not be serialized. This is only used temporarily -// and is restored into the state. -type sensitiveState struct { - ConnInfo map[string]map[string]string - - once sync.Once -} - -func (s *sensitiveState) init() { - s.once.Do(func() { - s.ConnInfo = make(map[string]map[string]string) - }) -} - -// The format byte is prefixed into the state file format so that we have -// the ability in the future to change the file format if we want for any -// reason. -const stateFormatMagic = "tfstate" -const stateFormatVersion byte = 1 - /// ResourceState holds the state of a resource that is used so that // a provider can find and manage an existing resource as well as for // storing attributes that are uesd to populate variables of child @@ -236,8 +226,8 @@ type ResourceStateV1 struct { // If the diff attribute requires computing the value, and hence // won't be available until apply, the value is replaced with the // computeID. -func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { - var result ResourceState +func (s *ResourceStateV1) MergeDiff(d *ResourceDiff) *ResourceStateV1 { + var result ResourceStateV1 if s != nil { result = *s } @@ -266,7 +256,7 @@ func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { return &result } -func (s *ResourceState) GoString() string { +func (s *ResourceStateV1) GoString() string { return fmt.Sprintf("*%#v", *s) } @@ -277,3 +267,45 @@ type ResourceDependency struct { // directly to another ResourceState's ID. ID string } + +// ReadStateV1 reads a state structure out of a reader in the format that +// was written by WriteState. +func ReadStateV1(src io.Reader) (*StateV1, error) { + var result *StateV1 + var err error + n := 0 + + // Verify the magic bytes + magic := make([]byte, len(stateFormatMagic)) + for n < len(magic) { + n, err = src.Read(magic[n:]) + if err != nil { + return nil, fmt.Errorf("error while reading magic bytes: %s", err) + } + } + if string(magic) != stateFormatMagic { + return nil, fmt.Errorf("not a valid state file") + } + + // Verify the version is something we can read + var formatByte [1]byte + n, err = src.Read(formatByte[:]) + if err != nil { + return nil, err + } + if n != len(formatByte) { + return nil, errors.New("failed to read state version byte") + } + + if formatByte[0] != stateFormatVersion { + return nil, fmt.Errorf("unknown state file version: %d", formatByte[0]) + } + + // Decode + dec := gob.NewDecoder(src) + if err := dec.Decode(&result); err != nil { + return nil, err + } + + return result, nil +} From bb26c7942121cd58d3f2e55ace07415295069b3f Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 16:08:13 -0700 Subject: [PATCH 03/85] terraform: Adding deepcopy() to new state --- terraform/state.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index 281893e24..6f9373de7 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -23,6 +23,18 @@ type State struct { Modules []*ModuleState `json:"modules"` } +func (s *State) deepcopy() *State { + n := &State{ + Version: n.Version, + Serial: n.Serial, + Modules: make([]*ModuleState, 0, len(s.Modules)), + } + for _, mod := range s.Modules { + n.Modules = append(n.Modules, mod.deepcopy()) + } + return n +} + // ModuleState is used to track all the state relevant to a single // module. Previous to Terraform 0.3, all state belonged to the "root" // module. @@ -43,6 +55,22 @@ type ModuleState struct { Resources map[string]*ResourceState `json:"resources"` } +func (m *ModuleState) deepcopy() *ModuleState { + n := &ModuleState{ + Path: make([]string, len(m.Path)), + Outputs: make(map[string]string, len(m.Outputs)), + Resources: make(map[string]*ResourceState, len(m.Resources)), + } + copy(n.Path, m.Path) + for k, v := range m.Outputs { + n.Outputs[k] = v + } + for k, v := range m.Resources { + n.Resources[k] = v.deepcopy() + } + return n +} + // ResourceState holds the state of a resource that is used so that // a provider can find and manage an existing resource as well as for // storing attributes that are used to populate variables of child @@ -85,6 +113,19 @@ type ResourceState struct { Instances []*InstanceState `json:"instances"` } +func (r *ResourceState) deepcopy() *ResourceState { + n := &ResourceState{ + Type: r.Type, + Dependencies: make([]string, len(r.Dependencies)), + Instances: make([]*Instances, 0, len(r.Instances)), + } + copy(n.Dependencies, r.Dependencies) + for _, inst := range r.Instances { + n.Instances = append(n.Instances, inst.deepcopy()) + } + return n +} + // InstanceState is used to track the unique state information belonging // to a given instance. type InstanceState struct { @@ -108,6 +149,19 @@ type InstanceState struct { Ephemeral EphemeralState `json:"-"` } +func (i *InstanceState) deepcopy() *InstanceState { + n := &InstanceState{ + ID: i.ID, + Tainted: i.Tainted, + Attributes: make(map[string]string, len(i.Attributes)), + Ephemeral: *i.EphemeralState.deepcopy(), + } + for k, v := range i.Attributes { + n.Attributes[k] = v + } + return n +} + // EphemeralState is used for transient state that is only kept in-memory type EphemeralState struct { // ConnInfo is used for the providers to export information which is @@ -116,6 +170,16 @@ type EphemeralState struct { ConnInfo map[string]string `json:"-"` } +func (e *EphemeralState) deepcopy() *EphemeralState { + n := &EphemeralState{ + ConnInfo: make(map[string]string, len(n.ConnInfo)), + } + for k, v := range e.ConnInfo { + n.ConnInfo[k] = v + } + return n +} + // ReadState reads a state structure out of a reader in the format that // was written by WriteState. func ReadState(src io.Reader) (*State, error) { From ab7ae0516cc15cd0b5ae8b4081ef4fd298bdc173 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 17:06:32 -0700 Subject: [PATCH 04/85] terraform: handle state pruning --- terraform/state.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index 6f9373de7..a98bc8c39 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -35,6 +35,13 @@ func (s *State) deepcopy() *State { return n } +// prune is used to remove any resources that are no longer required +func (s *State) prune() { + for _, mod := range m.Modules { + mod.prune() + } +} + // ModuleState is used to track all the state relevant to a single // module. Previous to Terraform 0.3, all state belonged to the "root" // module. @@ -71,6 +78,16 @@ func (m *ModuleState) deepcopy() *ModuleState { return n } +// prune is used to remove any resources that are no longer required +func (m *ModuleState) prune() { + for k, v := range m.Resources { + v.prune() + if len(v.instances) == 0 { + delete(m.Resources, k) + } + } +} + // ResourceState holds the state of a resource that is used so that // a provider can find and manage an existing resource as well as for // storing attributes that are used to populate variables of child @@ -126,6 +143,20 @@ func (r *ResourceState) deepcopy() *ResourceState { return n } +// prune is used to remove any instances that are no longer required +func (r *ResourceState) prune() { + n := len(r.Instances) + for i := 0; i < n; i++ { + inst := r.Instances[i] + if inst.ID == "" { + copy(r.Instances[i:], r.Instances[i+1:]) + r.Instances[n-1] = nil + n-- + } + } + r.Instances = r.Instances[:n] +} + // InstanceState is used to track the unique state information belonging // to a given instance. type InstanceState struct { From a85d6fa6c3a05d861febb3a893b29b3dbb0bb229 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 17:11:36 -0700 Subject: [PATCH 05/85] terraform: Adding module lookups for state --- terraform/context.go | 10 ++++++---- terraform/state.go | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 61d6ad509..2bdf0935f 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -131,15 +131,17 @@ func (c *Context) Apply() (*State, error) { c.state.prune() // If we have no errors, then calculate the outputs if we have any - if err == nil && len(c.config.Outputs) > 0 && len(c.state.Resources) > 0 { - c.state.Outputs = make(map[string]string) + if err == nil && len(c.config.Outputs) > 0 { + outputs := make(map[string]string) for _, o := range c.config.Outputs { if err = c.computeVars(o.RawConfig); err != nil { break } - - c.state.Outputs[o.Name] = o.RawConfig.Config()["value"].(string) + outputs[o.Name] = o.RawConfig.Config()["value"].(string) } + + // Assign the outputs to the root module + c.state.RootModule().Outputs = outputs } return c.state, err diff --git a/terraform/state.go b/terraform/state.go index a98bc8c39..44a763dc4 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -7,6 +7,9 @@ import ( "io" ) +// rootModulePath is the path of the root module +var rootModulePath = []string{"root"} + // State keeps track of a snapshot state-of-the-world that Terraform // can use to keep track of what real world resources it is actually // managing. This is the latest format as of Terraform 0.3 @@ -23,6 +26,23 @@ type State struct { Modules []*ModuleState `json:"modules"` } +// ModuleByPath is used to lookup the module state for the given path. +// This should be the prefered lookup mechanism as it allows for future +// lookup optimizations. +func (s *State) ModuleByPath(path []string) *ModuleState { + for _, mod := range s.Modules { + if reflect.Equal(mod.Path, path) { + return mod + } + } + return nil +} + +// RootModule returns the ModuleState for the root module +func (s *State) RootModule() *ModuleState { + return s.ModuleByPath(rootModulePath) +} + func (s *State) deepcopy() *State { n := &State{ Version: n.Version, From f5fc4933e5d2dac40ff37f560bd4190b8359be4a Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 17:30:18 -0700 Subject: [PATCH 06/85] terraform: working through errors --- terraform/context.go | 20 +++++++++++++++----- terraform/state.go | 6 ++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 2bdf0935f..4856f71d9 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -360,7 +360,11 @@ func (c *Context) computeResourceVariable( c.sl.RLock() defer c.sl.RUnlock() - r, ok := c.state.Resources[id] + // Get the relevant module + // TODO: Not use only root module + module := c.state.RootModule() + + r, ok := module.Resources[id] if !ok { return "", fmt.Errorf( "Resource '%s' not found for variable '%s'", @@ -368,7 +372,8 @@ func (c *Context) computeResourceVariable( v.FullKey()) } - attr, ok := r.Attributes[v.Field] + primary := r.Primary() + attr, ok := primary.Attributes[v.Field] if ok { return attr, nil } @@ -381,7 +386,7 @@ func (c *Context) computeResourceVariable( if len(parts) > 1 { for i := 1; i < len(parts); i++ { key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) - if attr, ok := r.Attributes[key]; ok { + if attr, ok := primary.Attributes[key]; ok { return attr, nil } } @@ -416,6 +421,10 @@ func (c *Context) computeResourceMultiVariable( v.FullKey()) } + // Get the relevant module + // TODO: Not use only root module + module := c.state.RootModule() + var values []string for i := 0; i < cr.Count; i++ { id := fmt.Sprintf("%s.%d", v.ResourceId(), i) @@ -426,12 +435,13 @@ func (c *Context) computeResourceMultiVariable( id = v.ResourceId() } - r, ok := c.state.Resources[id] + r, ok := module.Resources[id] if !ok { continue } - attr, ok := r.Attributes[v.Field] + primary := r.Primary() + attr, ok := primary.Attributes[v.Field] if !ok { continue } diff --git a/terraform/state.go b/terraform/state.go index 44a763dc4..65d9eadb0 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -150,6 +150,12 @@ type ResourceState struct { Instances []*InstanceState `json:"instances"` } +// Primary is used to return the primary instance. This is the +// active instance that should be used for attribute interpolation +func (r *ResourceState) Primary() *InstanceState { + return r.Instances[0] +} + func (r *ResourceState) deepcopy() *ResourceState { n := &ResourceState{ Type: r.Type, From 9cbd71b88d2f3a00a4f3e9ab87ebef6f2a3c241e Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 15 Sep 2014 17:49:31 -0700 Subject: [PATCH 07/85] terraform: Changing how instances are represented --- terraform/context.go | 12 +++++------- terraform/state.go | 30 +++++++++++++++++------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 4856f71d9..3572508c0 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -372,8 +372,7 @@ func (c *Context) computeResourceVariable( v.FullKey()) } - primary := r.Primary() - attr, ok := primary.Attributes[v.Field] + attr, ok := r.Primary.Attributes[v.Field] if ok { return attr, nil } @@ -386,7 +385,7 @@ func (c *Context) computeResourceVariable( if len(parts) > 1 { for i := 1; i < len(parts); i++ { key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) - if attr, ok := primary.Attributes[key]; ok { + if attr, ok := r.Primary.Attributes[key]; ok { return attr, nil } } @@ -440,8 +439,7 @@ func (c *Context) computeResourceMultiVariable( continue } - primary := r.Primary() - attr, ok := primary.Attributes[v.Field] + attr, ok := r.Primary.Attributes[v.Field] if !ok { continue } @@ -546,8 +544,8 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } // If we do not have any connection info, initialize - if r.State.ConnInfo == nil { - r.State.ConnInfo = make(map[string]string) + if r.State.Primary.Ephemeral.ConnInfo == nil { + r.State.Primary.Ephemeral.init() } // Remove any output values from the diff diff --git a/terraform/state.go b/terraform/state.go index 65d9eadb0..ed77c2b71 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -140,20 +140,18 @@ type ResourceState struct { // worry about it. Dependencies []string `json:"depends_on,omitempty"` - // Instances is used to track all of the underlying instances - // have been created as part of this logical resource. In the - // standard case, there is only a single underlying instance. - // However, in pathological cases, it is possible for the number - // of instances to accumulate. The first instance in the list is - // the "primary" and the others should be removed on subsequent - // apply operations. - Instances []*InstanceState `json:"instances"` -} + // Primary is the current active instance for this resource. + // It can be replaced but only after a successful creation. + // This is the instances on which providers will act. + Primary *InstanceState `json:"primary"` -// Primary is used to return the primary instance. This is the -// active instance that should be used for attribute interpolation -func (r *ResourceState) Primary() *InstanceState { - return r.Instances[0] + // Tainted is used to track any underlying instances that + // have been created but are in a bad or unknown state and + // need to be cleaned up subsequently. In the + // standard case, there is only at most a single instance. + // However, in pathological cases, it is possible for the number + // of instances to accumulate. + Tainted []*InstanceState `json:"tainted,omitempty"` } func (r *ResourceState) deepcopy() *ResourceState { @@ -227,6 +225,12 @@ type EphemeralState struct { ConnInfo map[string]string `json:"-"` } +func (e *EphemeralState) init() { + if e.ConnInfo == nil { + e.ConnInfo = make(map[string]string) + } +} + func (e *EphemeralState) deepcopy() *EphemeralState { n := &EphemeralState{ ConnInfo: make(map[string]string, len(n.ConnInfo)), From 3963b426253a65aeae9833dd86eef56bacad65c8 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 12:12:15 -0700 Subject: [PATCH 08/85] terraform: Fixing up context --- terraform/context.go | 73 +++++++++++++++++++++----------------------- terraform/state.go | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 38 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 3572508c0..da4d707cd 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -505,6 +505,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return nil } + // Ensure the state is initialized + r.State.init() + if !diff.Destroy { // Since we need the configuration, interpolate the variables if err := r.Config.interpolate(c); err != nil { @@ -543,11 +546,6 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } } - // If we do not have any connection info, initialize - if r.State.Primary.Ephemeral.ConnInfo == nil { - r.State.Primary.Ephemeral.init() - } - // Remove any output values from the diff for k, ad := range diff.Attributes { if ad.Type == DiffAttrOutput { @@ -571,42 +569,36 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // Make sure the result is instantiated if rs == nil { rs = new(ResourceState) + rs.init() } // Force the resource state type to be our type rs.Type = r.State.Type // Force the "id" attribute to be our ID - if rs.ID != "" { - if rs.Attributes == nil { - rs.Attributes = make(map[string]string) - } - - rs.Attributes["id"] = rs.ID + if rs.Primary.ID != "" { + rs.Primary.Attributes["id"] = rs.Primary.ID } - for ak, av := range rs.Attributes { + for ak, av := range rs.Primary.Attributes { // If the value is the unknown variable value, then it is an error. // In this case we record the error and remove it from the state if av == config.UnknownVariableValue { errs = append(errs, fmt.Errorf( "Attribute with unknown value: %s", ak)) - delete(rs.Attributes, ak) + delete(rs.Primary.Attributes, ak) } } // Update the resulting diff c.sl.Lock() - if rs.ID == "" { - delete(c.state.Resources, r.Id) - delete(c.state.Tainted, r.Id) - } else { - c.state.Resources[r.Id] = rs - // We always mark the resource as tainted here in case a - // hook below during provisioning does HookActionStop. This - // way, we keep the resource tainted. - c.state.Tainted[r.Id] = struct{}{} + // TODO: Get other modules + mod := c.state.RootModule() + if rs.Primary.ID == "" && len(rs.Tainted) == 0 { + delete(mod.Resources, r.Id) + } else { + mod.Resources[r.Id] = rs } c.sl.Unlock() @@ -617,7 +609,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // Additionally, we need to be careful to not run this if there // was an error during the provider apply. tainted := false - if applyerr == nil && r.State.ID == "" && len(r.Provisioners) > 0 { + if applyerr == nil && r.State.Primary.ID == "" && len(r.Provisioners) > 0 { for _, h := range c.hooks { handleHook(h.PreProvisionResource(r.Id, r.State)) } @@ -635,9 +627,8 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { c.sl.Lock() if tainted { log.Printf("[DEBUG] %s: Marking as tainted", r.Id) - c.state.Tainted[r.Id] = struct{}{} - } else { - delete(c.state.Tainted, r.Id) + rs.Tainted = append(rs.Tainted, rs.Primary) + rs.Primary = nil } c.sl.Unlock() @@ -665,9 +656,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // defined after the resource creation has already completed. func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error { // Store the original connection info, restore later - origConnInfo := rs.ConnInfo + origConnInfo := rs.Primary.Ephemeral.ConnInfo defer func() { - rs.ConnInfo = origConnInfo + rs.Primary.Ephemeral.ConnInfo = origConnInfo }() for _, prov := range r.Provisioners { @@ -710,7 +701,7 @@ func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error { overlay[k] = fmt.Sprintf("%v", vt) } } - rs.ConnInfo = overlay + rs.Primary.Ephemeral.ConnInfo = overlay // Invoke the Provisioner for _, h := range c.hooks { @@ -778,16 +769,16 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { diff.Destroy = true } - if diff.RequiresNew() && r.State.ID != "" { + if diff.RequiresNew() && r.State.Primary.ID != "" { // This will also require a destroy diff.Destroy = true } - if diff.RequiresNew() || r.State.ID == "" { + if diff.RequiresNew() || r.State.Primary.ID == "" { // Add diff to compute new ID diff.init() diff.Attributes["id"] = &ResourceAttrDiff{ - Old: r.State.Attributes["id"], + Old: r.State.Primary.Attributes["id"], NewComputed: true, RequiresNew: true, Type: DiffAttrOutput, @@ -812,7 +803,10 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { // Update our internal state so that variable computation works c.sl.Lock() defer c.sl.Unlock() - c.state.Resources[r.Id] = r.State + + // TODO: Handle other modules + mod := c.state.RootModule() + mod.Resources[r.Id] = r.State return nil } @@ -833,7 +827,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } r := rn.Resource - if r.State.ID != "" { + if r.State.Primary.ID != "" { log.Printf("[DEBUG] %s: Making for destroy", r.Id) l.Lock() @@ -849,7 +843,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { - if r.State.ID == "" { + if r.State.Primary.ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) return nil } @@ -870,10 +864,13 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { rs.Type = r.State.Type c.sl.Lock() - if rs.ID == "" { - delete(c.state.Resources, r.Id) + + // TODO: Handle other moduels + mod := c.state.RootModule() + if rs.Primary.ID == "" { + delete(mod.Resources, r.Id) } else { - c.state.Resources[r.Id] = rs + mod.Resources[r.Id] = rs } c.sl.Unlock() diff --git a/terraform/state.go b/terraform/state.go index ed77c2b71..a00aa4737 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "io" + + "github.com/hashicorp/terraform/config" ) // rootModulePath is the path of the root module @@ -82,6 +84,15 @@ type ModuleState struct { Resources map[string]*ResourceState `json:"resources"` } +func (m *ModuleState) init() { + if m.Outputs == nil { + m.Outputs = make(map[string]stirng) + } + if m.Resources == nil { + m.Resources = make(map[string]*ResourceState) + } +} + func (m *ModuleState) deepcopy() *ModuleState { n := &ModuleState{ Path: make([]string, len(m.Path)), @@ -154,6 +165,13 @@ type ResourceState struct { Tainted []*InstanceState `json:"tainted,omitempty"` } +func (r *ResourceState) init() { + if i.Primary == nil { + i.Primary = &InstanceState{} + i.Primary.init() + } +} + func (r *ResourceState) deepcopy() *ResourceState { n := &ResourceState{ Type: r.Type, @@ -181,6 +199,44 @@ func (r *ResourceState) prune() { r.Instances = r.Instances[:n] } +// MergeDiff takes a ResourceDiff and merges the attributes into +// this resource state in order to generate a new state. This new +// state can be used to provide updated attribute lookups for +// variable interpolation. +// +// If the diff attribute requires computing the value, and hence +// won't be available until apply, the value is replaced with the +// computeID. +func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { + var result ResourceState + if s != nil { + result = *s + } + result.init() + + if s != nil { + for k, v := range s.Primary.Attributes { + result.Primary.Attributes[k] = v + } + } + if d != nil { + for k, diff := range d.Attributes { + if diff.NewRemoved { + delete(result.Primary.Attributes, k) + continue + } + if diff.NewComputed { + result.Primary.Attributes[k] = config.UnknownVariableValue + continue + } + + result.Primary.Attributes[k] = diff.New + } + } + + return &result +} + // InstanceState is used to track the unique state information belonging // to a given instance. type InstanceState struct { @@ -204,6 +260,13 @@ type InstanceState struct { Ephemeral EphemeralState `json:"-"` } +func (i *InstanceState) init() { + if i.Attributes == nil { + i.Attributes = make(map[string]string) + } + i.Ephemeral.init() +} + func (i *InstanceState) deepcopy() *InstanceState { n := &InstanceState{ ID: i.ID, From f4678c8fcdf42cf7123fd1e93a7d7718af28076f Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 12:33:45 -0700 Subject: [PATCH 09/85] terraform: Fixing type references --- terraform/state_v1.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/terraform/state_v1.go b/terraform/state_v1.go index d1f44c554..fc0a90f5a 100644 --- a/terraform/state_v1.go +++ b/terraform/state_v1.go @@ -25,7 +25,7 @@ const ( // on start. type StateV1 struct { Outputs map[string]string - Resources map[string]*ResourceState + Resources map[string]*ResourceStateV1 Tainted map[string]struct{} once sync.Once @@ -34,7 +34,7 @@ type StateV1 struct { func (s *StateV1) init() { s.once.Do(func() { if s.Resources == nil { - s.Resources = make(map[string]*ResourceState) + s.Resources = make(map[string]*ResourceStateV1) } if s.Tainted == nil { @@ -43,8 +43,8 @@ func (s *StateV1) init() { }) } -func (s *StateV1) deepcopy() *State { - result := new(State) +func (s *StateV1) deepcopy() *StateV1 { + result := new(StateV1) result.init() if s != nil { for k, v := range s.Resources { From 04a2b5288bc65f2fbe67014b9d1bb16a34898b7a Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 12:34:08 -0700 Subject: [PATCH 10/85] terraform: fixing errors --- terraform/state.go | 177 +++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 95 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index a00aa4737..1342aada9 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1,10 +1,9 @@ package terraform import ( - "encoding/gob" - "errors" "fmt" "io" + "reflect" "github.com/hashicorp/terraform/config" ) @@ -33,7 +32,7 @@ type State struct { // lookup optimizations. func (s *State) ModuleByPath(path []string) *ModuleState { for _, mod := range s.Modules { - if reflect.Equal(mod.Path, path) { + if reflect.DeepEqual(mod.Path, path) { return mod } } @@ -46,9 +45,12 @@ func (s *State) RootModule() *ModuleState { } func (s *State) deepcopy() *State { + if s == nil { + return nil + } n := &State{ - Version: n.Version, - Serial: n.Serial, + Version: s.Version, + Serial: s.Serial, Modules: make([]*ModuleState, 0, len(s.Modules)), } for _, mod := range s.Modules { @@ -59,11 +61,15 @@ func (s *State) deepcopy() *State { // prune is used to remove any resources that are no longer required func (s *State) prune() { - for _, mod := range m.Modules { + for _, mod := range s.Modules { mod.prune() } } +func (s *State) GoString() string { + return fmt.Sprintf("*%#v", *s) +} + // ModuleState is used to track all the state relevant to a single // module. Previous to Terraform 0.3, all state belonged to the "root" // module. @@ -84,9 +90,35 @@ type ModuleState struct { Resources map[string]*ResourceState `json:"resources"` } +// Orphans returns a list of keys of resources that are in the State +// but aren't present in the configuration itself. Hence, these keys +// represent the state of resources that are orphans. +func (m *ModuleState) Orphans(c *config.Config) []string { + keys := make(map[string]struct{}) + for k, _ := range m.Resources { + keys[k] = struct{}{} + } + + for _, r := range c.Resources { + delete(keys, r.Id()) + + // Mark all the counts as not orphans. + for i := 0; i < r.Count; i++ { + delete(keys, fmt.Sprintf("%s.%d", r.Id(), i)) + } + } + + result := make([]string, 0, len(keys)) + for k, _ := range keys { + result = append(result, k) + } + + return result +} + func (m *ModuleState) init() { if m.Outputs == nil { - m.Outputs = make(map[string]stirng) + m.Outputs = make(map[string]string) } if m.Resources == nil { m.Resources = make(map[string]*ResourceState) @@ -94,6 +126,9 @@ func (m *ModuleState) init() { } func (m *ModuleState) deepcopy() *ModuleState { + if m == nil { + return nil + } n := &ModuleState{ Path: make([]string, len(m.Path)), Outputs: make(map[string]string, len(m.Outputs)), @@ -113,12 +148,16 @@ func (m *ModuleState) deepcopy() *ModuleState { func (m *ModuleState) prune() { for k, v := range m.Resources { v.prune() - if len(v.instances) == 0 { + if (v.Primary == nil || v.Primary.ID == "") && len(v.Tainted) == 0 { delete(m.Resources, k) } } } +func (m *ModuleState) GoString() string { + return fmt.Sprintf("*%#v", *m) +} + // ResourceState holds the state of a resource that is used so that // a provider can find and manage an existing resource as well as for // storing attributes that are used to populate variables of child @@ -166,37 +205,45 @@ type ResourceState struct { } func (r *ResourceState) init() { - if i.Primary == nil { - i.Primary = &InstanceState{} - i.Primary.init() + if r.Primary == nil { + r.Primary = &InstanceState{} + r.Primary.init() } } func (r *ResourceState) deepcopy() *ResourceState { + if r == nil { + return nil + } n := &ResourceState{ Type: r.Type, Dependencies: make([]string, len(r.Dependencies)), - Instances: make([]*Instances, 0, len(r.Instances)), + Primary: r.Primary.deepcopy(), + Tainted: make([]*InstanceState, 0, len(r.Tainted)), } copy(n.Dependencies, r.Dependencies) - for _, inst := range r.Instances { - n.Instances = append(n.Instances, inst.deepcopy()) + for _, inst := range r.Tainted { + n.Tainted = append(n.Tainted, inst.deepcopy()) } return n } // prune is used to remove any instances that are no longer required func (r *ResourceState) prune() { - n := len(r.Instances) + n := len(r.Tainted) for i := 0; i < n; i++ { - inst := r.Instances[i] + inst := r.Tainted[i] if inst.ID == "" { - copy(r.Instances[i:], r.Instances[i+1:]) - r.Instances[n-1] = nil + copy(r.Tainted[i:], r.Tainted[i+1:]) + r.Tainted[n-1] = nil n-- } } - r.Instances = r.Instances[:n] + r.Tainted = r.Tainted[:n] +} + +func (s *ResourceState) GoString() string { + return fmt.Sprintf("*%#v", *s) } // MergeDiff takes a ResourceDiff and merges the attributes into @@ -268,11 +315,14 @@ func (i *InstanceState) init() { } func (i *InstanceState) deepcopy() *InstanceState { + if i == nil { + return nil + } n := &InstanceState{ ID: i.ID, Tainted: i.Tainted, Attributes: make(map[string]string, len(i.Attributes)), - Ephemeral: *i.EphemeralState.deepcopy(), + Ephemeral: *i.Ephemeral.deepcopy(), } for k, v := range i.Attributes { n.Attributes[k] = v @@ -280,6 +330,10 @@ func (i *InstanceState) deepcopy() *InstanceState { return n } +func (i *InstanceState) GoString() string { + return fmt.Sprintf("*%#v", *i) +} + // EphemeralState is used for transient state that is only kept in-memory type EphemeralState struct { // ConnInfo is used for the providers to export information which is @@ -295,8 +349,11 @@ func (e *EphemeralState) init() { } func (e *EphemeralState) deepcopy() *EphemeralState { + if e == nil { + return nil + } n := &EphemeralState{ - ConnInfo: make(map[string]string, len(n.ConnInfo)), + ConnInfo: make(map[string]string, len(e.ConnInfo)), } for k, v := range e.ConnInfo { n.ConnInfo[k] = v @@ -307,82 +364,12 @@ func (e *EphemeralState) deepcopy() *EphemeralState { // ReadState reads a state structure out of a reader in the format that // was written by WriteState. func ReadState(src io.Reader) (*State, error) { - var result *State - var err error - n := 0 - - // Verify the magic bytes - magic := make([]byte, len(stateFormatMagic)) - for n < len(magic) { - n, err = src.Read(magic[n:]) - if err != nil { - return nil, fmt.Errorf("error while reading magic bytes: %s", err) - } - } - if string(magic) != stateFormatMagic { - return nil, fmt.Errorf("not a valid state file") - } - - // Verify the version is something we can read - var formatByte [1]byte - n, err = src.Read(formatByte[:]) - if err != nil { - return nil, err - } - if n != len(formatByte) { - return nil, errors.New("failed to read state version byte") - } - - if formatByte[0] != stateFormatVersion { - return nil, fmt.Errorf("unknown state file version: %d", formatByte[0]) - } - - // Decode - dec := gob.NewDecoder(src) - if err := dec.Decode(&result); err != nil { - return nil, err - } - - return result, nil + // TODO + return nil, nil } // WriteState writes a state somewhere in a binary format. func WriteState(d *State, dst io.Writer) error { - // Write the magic bytes so we can determine the file format later - n, err := dst.Write([]byte(stateFormatMagic)) - if err != nil { - return err - } - if n != len(stateFormatMagic) { - return errors.New("failed to write state format magic bytes") - } - - // Write a version byte so we can iterate on version at some point - n, err = dst.Write([]byte{stateFormatVersion}) - if err != nil { - return err - } - if n != 1 { - return errors.New("failed to write state version byte") - } - - // Prevent sensitive information from being serialized - sensitive := &sensitiveState{} - sensitive.init() - for name, r := range d.Resources { - if r.ConnInfo != nil { - sensitive.ConnInfo[name] = r.ConnInfo - r.ConnInfo = nil - } - } - - // Serialize the state - err = gob.NewEncoder(dst).Encode(d) - - // Restore the state - for name, info := range sensitive.ConnInfo { - d.Resources[name].ConnInfo = info - } - - return err + // TODO + return nil } From 3404277f3135e21cf435c7f0347521af8d6f1494 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 12:34:21 -0700 Subject: [PATCH 11/85] terraform: porting to new state --- terraform/graph.go | 32 ++++++++++++++++++++------------ terraform/graph_dot.go | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index f27ff23ea..ef09fc707 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -188,30 +188,36 @@ func graphAddConfigResources( index = i } - // Determine if this resource is tainted tainted := false - if s != nil && s.Tainted != nil { - _, tainted = s.Tainted[r.Id()] - } - + var mod *ModuleState var state *ResourceState - if s != nil { - state = s.Resources[name] + if s != nil { + // TODO: Handle non-root modules + mod = s.RootModule() + + // Lookup the resource state + state = mod.Resources[name] if state == nil { if r.Count == 1 { // If the count is one, check the state for ".0" // appended, which might exist if we go from // count > 1 to count == 1. - state = s.Resources[r.Id()+".0"] + state = mod.Resources[r.Id()+".0"] } else if i == 0 { // If count is greater than one, check for state // with just the ID, which might exist if we go // from count == 1 to count > 1 - state = s.Resources[r.Id()] + state = mod.Resources[r.Id()] } } + + // Determine if this resource is tainted + if state != nil && len(state.Tainted) > 0 { + tainted = true + } } + if state == nil { state = &ResourceState{ Type: r.Type, @@ -382,7 +388,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { } rn2 := n2.Meta.(*GraphNodeResource) - if rn2.Resource.State.ID == dep.ID { + if rn2.Resource.Id == dep { n2.Deps = append(n2.Deps, &depgraph.Dependency{ Name: n.Name, Source: n2, @@ -504,8 +510,10 @@ func graphAddMissingResourceProviders( // graphAddOrphans adds the orphans to the graph. func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { - for _, k := range s.Orphans(c) { - rs := s.Resources[k] + // TODO: Handle other modules + mod := s.RootModule() + for _, k := range mod.Orphans(c) { + rs := mod.Resources[k] noun := &depgraph.Noun{ Name: k, Meta: &GraphNodeResource{ diff --git a/terraform/graph_dot.go b/terraform/graph_dot.go index 7b0d0d325..b7db917d0 100644 --- a/terraform/graph_dot.go +++ b/terraform/graph_dot.go @@ -79,7 +79,7 @@ func graphDotAddResources(buf *bytes.Buffer, g *depgraph.Graph) { // green = create. Destroy is in the next section. var color, fillColor string if rn.Resource.Diff != nil && !rn.Resource.Diff.Empty() { - if rn.Resource.State != nil && rn.Resource.State.ID != "" { + if rn.Resource.State != nil && rn.Resource.State.Primary.ID != "" { color = "#FFFF00" fillColor = "#FFFF94" } else { From 196991430bcbfddaaae3b11c2d036e12942ce1da Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 14:26:27 -0700 Subject: [PATCH 12/85] terraform: Resolving more errors --- terraform/resource.go | 2 +- terraform/state.go | 89 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/terraform/resource.go b/terraform/resource.go index e3435279e..f912382be 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -43,7 +43,7 @@ func (r *Resource) Vars() map[string]string { } vars := make(map[string]string) - for ak, av := range r.State.Attributes { + for ak, av := range r.State.Primary.Attributes { vars[fmt.Sprintf("%s.%s", r.Id, ak)] = av } diff --git a/terraform/state.go b/terraform/state.go index 1342aada9..e6878aa0f 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1,13 +1,20 @@ package terraform import ( + "bytes" "fmt" "io" "reflect" + "sort" "github.com/hashicorp/terraform/config" ) +const ( + // textStateVersion is the current version for our state file + textStateVersion = 1 +) + // rootModulePath is the path of the root module var rootModulePath = []string{"root"} @@ -44,6 +51,17 @@ func (s *State) RootModule() *ModuleState { return s.ModuleByPath(rootModulePath) } +func (s *State) init() { + if s.Version == 0 { + s.Version = textStateVersion + } + if len(s.Modules) == 0 { + root := &ModuleState{} + root.init() + s.Modules = []*ModuleState{root} + } +} + func (s *State) deepcopy() *State { if s == nil { return nil @@ -70,6 +88,77 @@ func (s *State) GoString() string { return fmt.Sprintf("*%#v", *s) } +func (s *State) String() string { + // TODO: Handle other moduels + mod := s.RootModule() + if len(mod.Resources) == 0 { + return "" + } + + var buf bytes.Buffer + + names := make([]string, 0, len(mod.Resources)) + for name, _ := range mod.Resources { + names = append(names, name) + } + sort.Strings(names) + + for _, k := range names { + rs := mod.Resources[k] + id := rs.Primary.ID + if id == "" { + id = "" + } + + taintStr := "" + if len(rs.Tainted) > 0 { + taintStr = " (tainted)" + } + + buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) + buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) + + attrKeys := make([]string, 0, len(rs.Primary.Attributes)) + for ak, _ := range rs.Primary.Attributes { + if ak == "id" { + continue + } + + attrKeys = append(attrKeys, ak) + } + sort.Strings(attrKeys) + + for _, ak := range attrKeys { + av := rs.Primary.Attributes[ak] + buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) + } + + if len(rs.Dependencies) > 0 { + buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) + for _, dep := range rs.Dependencies { + buf.WriteString(fmt.Sprintf(" %s\n", dep)) + } + } + } + + if len(mod.Outputs) > 0 { + buf.WriteString("\nOutputs:\n\n") + + ks := make([]string, 0, len(mod.Outputs)) + for k, _ := range mod.Outputs { + ks = append(ks, k) + } + sort.Strings(ks) + + for _, k := range ks { + v := mod.Outputs[k] + buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) + } + } + + return buf.String() +} + // ModuleState is used to track all the state relevant to a single // module. Previous to Terraform 0.3, all state belonged to the "root" // module. From 4b0f970659f1f6d38f63bbc5fdc0e7e3e35bb134 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 15:09:40 -0700 Subject: [PATCH 13/85] terraform: fixing test errors --- terraform/context_test.go | 493 +++++++++++++++++++++++++------------ terraform/graph_test.go | 43 ++-- terraform/plan_test.go | 13 +- terraform/resource_test.go | 6 +- terraform/state.go | 10 +- terraform/state_test.go | 103 ++++++-- 6 files changed, 463 insertions(+), 205 deletions(-) diff --git a/terraform/context_test.go b/terraform/context_test.go index 8e8f54bfd..fb5bd2f9d 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -71,10 +71,17 @@ func TestContextValidate_orphans(t *testing.T) { p := testProvider("aws") config := testConfig(t, "validate-good") state := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -348,8 +355,9 @@ func TestContextApply(t *testing.T) { t.Fatalf("err: %s", err) } - if len(state.Resources) < 2 { - t.Fatalf("bad: %#v", state.Resources) + mod := state.RootModule() + if len(mod.Resources) < 2 { + t.Fatalf("bad: %#v", mod.Resources) } actual := strings.TrimSpace(state.String()) @@ -441,9 +449,11 @@ func TestContextApply_cancel(t *testing.T) { } return &ResourceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", + }, }, }, nil } @@ -474,8 +484,9 @@ func TestContextApply_cancel(t *testing.T) { state := <-stateCh - if len(state.Resources) != 1 { - t.Fatalf("bad: %#v", state.Resources) + mod := state.RootModule() + if len(mod.Resources) != 1 { + t.Fatalf("bad: %#v", mod.Resources) } actual := strings.TrimSpace(state.String()) @@ -678,10 +689,17 @@ func TestContextApply_outputDiffVars(t *testing.T) { c := testConfig(t, "apply-good") p := testProvider("aws") s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.baz": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.baz": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -701,7 +719,7 @@ func TestContextApply_outputDiffVars(t *testing.T) { } result := s.MergeDiff(d) - result.ID = "foo" + result.Primary.ID = "foo" return result, nil } p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { @@ -732,12 +750,12 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) { pr := testProvisioner() p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { - if s.ConnInfo == nil { + if s.Primary.Ephemeral.ConnInfo == nil { t.Fatalf("ConnInfo not initialized") } result, _ := testApplyFn(s, d) - result.ConnInfo = map[string]string{ + result.Primary.Ephemeral.ConnInfo = map[string]string{ "type": "ssh", "host": "127.0.0.1", "port": "22", @@ -747,7 +765,7 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) { p.DiffFn = testDiffFn pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { - conn := rs.ConnInfo + conn := rs.Primary.Ephemeral.ConnInfo if conn["type"] != "telnet" { t.Fatalf("Bad: %#v", conn) } @@ -887,8 +905,9 @@ func TestContextApply_destroyOutputs(t *testing.T) { t.Fatalf("err: %s", err) } - if len(state.Resources) > 0 { - t.Fatalf("bad: %#v", state) + mod := state.RootModule() + if len(mod.Resources) > 0 { + t.Fatalf("bad: %#v", mod) } } @@ -896,10 +915,17 @@ func TestContextApply_destroyOrphan(t *testing.T) { c := testConfig(t, "apply-error") p := testProvider("aws") s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.baz": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.baz": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -917,7 +943,7 @@ func TestContextApply_destroyOrphan(t *testing.T) { } result := s.MergeDiff(d) - result.ID = "foo" + result.Primary.ID = "foo" return result, nil } p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { @@ -939,8 +965,9 @@ func TestContextApply_destroyOrphan(t *testing.T) { t.Fatalf("err: %s", err) } - if _, ok := state.Resources["aws_instance.baz"]; ok { - t.Fatalf("bad: %#v", state.Resources) + mod := state.RootModule() + if _, ok := mod.Resources["aws_instance.baz"]; ok { + t.Fatalf("bad: %#v", mod.Resources) } } @@ -959,16 +986,20 @@ func TestContextApply_error(t *testing.T) { p.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { if errored { state := &ResourceState{ - ID: "bar", + Primary: &InstanceState{ + ID: "bar", + }, } return state, fmt.Errorf("error") } errored = true return &ResourceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", + }, }, }, nil } @@ -1004,10 +1035,17 @@ func TestContextApply_errorPartial(t *testing.T) { c := testConfig(t, "apply-error") p := testProvider("aws") s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.bar": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -1026,9 +1064,11 @@ func TestContextApply_errorPartial(t *testing.T) { errored = true return &ResourceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", + }, }, }, nil } @@ -1051,8 +1091,9 @@ func TestContextApply_errorPartial(t *testing.T) { t.Fatal("should have error") } - if len(state.Resources) != 2 { - t.Fatalf("bad: %#v", state.Resources) + mod := state.RootModule() + if len(mod.Resources) != 2 { + t.Fatalf("bad: %#v", mod.Resources) } actual := strings.TrimSpace(state.String()) @@ -1104,8 +1145,8 @@ func TestContextApply_idAttr(t *testing.T) { p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { result := s.MergeDiff(d) - result.ID = "foo" - result.Attributes = map[string]string{ + result.Primary.ID = "foo" + result.Primary.Attributes = map[string]string{ "id": "bar", } @@ -1130,15 +1171,16 @@ func TestContextApply_idAttr(t *testing.T) { t.Fatalf("err: %s", err) } - rs, ok := state.Resources["aws_instance.foo"] + mod := state.RootModule() + rs, ok := mod.Resources["aws_instance.foo"] if !ok { t.Fatal("not in state") } - if rs.ID != "foo" { - t.Fatalf("bad: %#v", rs.ID) + if rs.Primary.ID != "foo" { + t.Fatalf("bad: %#v", rs.Primary.ID) } - if rs.Attributes["id"] != "foo" { - t.Fatalf("bad: %#v", rs.Attributes) + if rs.Primary.Attributes["id"] != "foo" { + t.Fatalf("bad: %#v", rs.Primary.Attributes) } } @@ -1232,19 +1274,25 @@ func TestContextApply_taint(t *testing.T) { p.ApplyFn = testApplyFn p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.bar": &ResourceState{ - ID: "baz", - Type: "aws_instance", - Attributes: map[string]string{ - "num": "2", - "type": "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Tainted: []*InstanceState{ + &InstanceState{ + ID: "baz", + Attributes: map[string]string{ + "num": "2", + "type": "aws_instance", + }, + }, + }, + }, }, }, }, - Tainted: map[string]struct{}{ - "aws_instance.bar": struct{}{}, - }, } ctx := testContext(t, &ContextOpts{ Config: c, @@ -1398,10 +1446,17 @@ func TestContextPlan_nil(t *testing.T) { "aws": testProviderFuncFixed(p), }, State: &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, }, @@ -1494,23 +1549,33 @@ func TestContextPlan_countDecreaseToOne(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo.0": &ResourceState{ - ID: "bar", - Type: "aws_instance", - Attributes: map[string]string{ - "foo": "foo", - "type": "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Resources: map[string]*ResourceState{ + "aws_instance.foo.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "foo": "foo", + "type": "aws_instance", + }, + }, + }, + "aws_instance.foo.1": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + "aws_instance.foo.2": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, }, }, - "aws_instance.foo.1": &ResourceState{ - ID: "bar", - Type: "aws_instance", - }, - "aws_instance.foo.2": &ResourceState{ - ID: "bar", - Type: "aws_instance", - }, }, } ctx := testContext(t, &ContextOpts{ @@ -1538,13 +1603,20 @@ func TestContextPlan_countIncreaseFromNotSet(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "bar", - Type: "aws_instance", - Attributes: map[string]string{ - "foo": "foo", - "type": "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "foo": "foo", + "type": "aws_instance", + }, + }, + }, }, }, }, @@ -1574,13 +1646,20 @@ func TestContextPlan_countIncreaseFromOne(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo.0": &ResourceState{ - ID: "bar", - Type: "aws_instance", - Attributes: map[string]string{ - "foo": "foo", - "type": "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "foo": "foo", + "type": "aws_instance", + }, + }, + }, }, }, }, @@ -1610,14 +1689,23 @@ func TestContextPlan_destroy(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.one": &ResourceState{ - ID: "bar", - Type: "aws_instance", - }, - "aws_instance.two": &ResourceState{ - ID: "baz", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.one": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + "aws_instance.two": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "baz", + }, + }, + }, }, }, } @@ -1649,11 +1737,18 @@ func TestContextPlan_diffVar(t *testing.T) { c := testConfig(t, "plan-diffvar") p := testProvider("aws") s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "bar", - Attributes: map[string]string{ - "num": "2", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "num": "2", + }, + }, + }, }, }, }, @@ -1668,7 +1763,7 @@ func TestContextPlan_diffVar(t *testing.T) { p.DiffFn = func( s *ResourceState, c *ResourceConfig) (*ResourceDiff, error) { - if s.ID != "bar" { + if s.Primary.ID != "bar" { return testDiffFn(s, c) } @@ -1725,10 +1820,17 @@ func TestContextPlan_orphan(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.baz": &ResourceState{ - ID: "bar", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.baz": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -1757,9 +1859,16 @@ func TestContextPlan_state(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "bar", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -1792,18 +1901,28 @@ func TestContextPlan_taint(t *testing.T) { p := testProvider("aws") p.DiffFn = testDiffFn s := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "bar", - Type: "aws_instance", - Attributes: map[string]string{"num": "2"}, - }, - "aws_instance.bar": &ResourceState{ - ID: "baz", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{"num": "2"}, + }, + }, + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Tainted: []*InstanceState{ + &InstanceState{ + ID: "baz", + }, + }, + }, + }, }, }, - Tainted: map[string]struct{}{"aws_instance.bar": struct{}{}}, } ctx := testContext(t, &ContextOpts{ Config: c, @@ -1857,10 +1976,17 @@ func TestContextRefresh(t *testing.T) { "aws": testProviderFuncFixed(p), }, State: &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "foo", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, }, }, }, @@ -1868,24 +1994,27 @@ func TestContextRefresh(t *testing.T) { p.RefreshFn = nil p.RefreshReturn = &ResourceState{ - ID: "foo", + Primary: &InstanceState{ + ID: "foo", + }, } s, err := ctx.Refresh() + mod := s.RootModule() if err != nil { t.Fatalf("err: %s", err) } if !p.RefreshCalled { t.Fatal("refresh should be called") } - if p.RefreshState.ID != "foo" { + if p.RefreshState.Primary.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(s.Resources["aws_instance.web"], p.RefreshReturn) { - t.Fatalf("bad: %#v", s.Resources["aws_instance.web"]) + if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) } - for _, r := range s.Resources { + for _, r := range mod.Resources { if r.Type == "" { t.Fatalf("no type: %#v", r) } @@ -1901,10 +2030,17 @@ func TestContextRefresh_delete(t *testing.T) { "aws": testProviderFuncFixed(p), }, State: &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "foo", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, }, }, }, @@ -1918,7 +2054,8 @@ func TestContextRefresh_delete(t *testing.T) { t.Fatalf("err: %s", err) } - if len(s.Resources) > 0 { + mod := s.RootModule() + if len(mod.Resources) > 0 { t.Fatal("resources should be empty") } } @@ -1936,7 +2073,9 @@ func TestContextRefresh_ignoreUncreated(t *testing.T) { p.RefreshFn = nil p.RefreshReturn = &ResourceState{ - ID: "foo", + Primary: &InstanceState{ + ID: "foo", + }, } _, err := ctx.Refresh() @@ -1959,10 +2098,17 @@ func TestContextRefresh_hook(t *testing.T) { "aws": testProviderFuncFixed(p), }, State: &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "foo", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, }, }, }, @@ -1989,9 +2135,16 @@ func TestContextRefresh_state(t *testing.T) { p := testProvider("aws") c := testConfig(t, "refresh-basic") state := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "bar", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -2005,21 +2158,24 @@ func TestContextRefresh_state(t *testing.T) { p.RefreshFn = nil p.RefreshReturn = &ResourceState{ - ID: "foo", + Primary: &InstanceState{ + ID: "foo", + }, } s, err := ctx.Refresh() if err != nil { t.Fatalf("err: %s", err) } + mod := s.RootModule() if !p.RefreshCalled { t.Fatal("refresh should be called") } - if !reflect.DeepEqual(p.RefreshState, state.Resources["aws_instance.web"]) { + if !reflect.DeepEqual(p.RefreshState, mod.Resources["aws_instance.web"]) { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(s.Resources["aws_instance.web"], p.RefreshReturn) { - t.Fatalf("bad: %#v", s.Resources) + if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + t.Fatalf("bad: %#v", mod.Resources) } } @@ -2032,10 +2188,18 @@ func TestContextRefresh_vars(t *testing.T) { "aws": testProviderFuncFixed(p), }, State: &State{ - Resources: map[string]*ResourceState{ - "aws_instance.web": &ResourceState{ - ID: "foo", - Type: "aws_instance", + + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, }, }, }, @@ -2043,24 +2207,27 @@ func TestContextRefresh_vars(t *testing.T) { p.RefreshFn = nil p.RefreshReturn = &ResourceState{ - ID: "foo", + Primary: &InstanceState{ + ID: "foo", + }, } s, err := ctx.Refresh() if err != nil { t.Fatalf("err: %s", err) } + mod := s.RootModule() if !p.RefreshCalled { t.Fatal("refresh should be called") } - if p.RefreshState.ID != "foo" { + if p.RefreshState.Primary.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(s.Resources["aws_instance.web"], p.RefreshReturn) { - t.Fatalf("bad: %#v", s.Resources["aws_instance.web"]) + if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) } - for _, r := range s.Resources { + for _, r := range mod.Resources { if r.Type == "" { t.Fatalf("no type: %#v", r) } @@ -2084,7 +2251,9 @@ func testApplyFn( } result := &ResourceState{ - ID: id, + Primary: &InstanceState{ + ID: id, + }, } if d != nil { @@ -2092,11 +2261,7 @@ func testApplyFn( } if depAttr, ok := d.Attributes["dep"]; ok { - result.Dependencies = []ResourceDependency{ - ResourceDependency{ - ID: depAttr.New, - }, - } + result.Dependencies = []string{depAttr.New} } return result, nil @@ -2173,7 +2338,7 @@ func testDiffFn( continue } - old, ok := s.Attributes[k] + old, ok := s.Primary.Attributes[k] if !ok { continue } diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 1d05942a5..60bb14d89 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -84,10 +84,18 @@ func TestGraph_dependsOnCount(t *testing.T) { func TestGraph_state(t *testing.T) { config := testConfig(t, "graph-basic") state := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.old": &ResourceState{ - ID: "foo", - Type: "aws_instance", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + + Resources: map[string]*ResourceState{ + "aws_instance.old": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, }, }, } @@ -289,18 +297,23 @@ func TestGraphAddDiff_destroy(t *testing.T) { }, } state := &State{ - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - ID: "foo", - Type: "aws_instance", - }, + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, - "aws_instance.bar": &ResourceState{ - ID: "bar", - Type: "aws_instance", - Dependencies: []ResourceDependency{ - ResourceDependency{ - ID: "foo", + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Dependencies: []string{"foo"}, + Primary: &InstanceState{ + ID: "bar", + }, }, }, }, diff --git a/terraform/plan_test.go b/terraform/plan_test.go index 63b0e216c..7531186c3 100644 --- a/terraform/plan_test.go +++ b/terraform/plan_test.go @@ -32,9 +32,16 @@ func TestReadWritePlan(t *testing.T) { }, }, State: &State{ - Resources: map[string]*ResourceState{ - "foo": &ResourceState{ - ID: "bar", + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "foo": &ResourceState{ + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, }, }, }, diff --git a/terraform/resource_test.go b/terraform/resource_test.go index fa35ab9a8..b8afb4e5d 100644 --- a/terraform/resource_test.go +++ b/terraform/resource_test.go @@ -17,8 +17,10 @@ func TestResource_Vars(t *testing.T) { r = &Resource{ Id: "key", State: &ResourceState{ - Attributes: map[string]string{ - "foo": "bar", + Primary: &InstanceState{ + Attributes: map[string]string{ + "foo": "bar", + }, }, }, } diff --git a/terraform/state.go b/terraform/state.go index e6878aa0f..69e89bac5 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -48,7 +48,11 @@ func (s *State) ModuleByPath(path []string) *ModuleState { // RootModule returns the ModuleState for the root module func (s *State) RootModule() *ModuleState { - return s.ModuleByPath(rootModulePath) + root := s.ModuleByPath(rootModulePath) + if root == nil { + panic("missing root module") + } + return root } func (s *State) init() { @@ -56,7 +60,9 @@ func (s *State) init() { s.Version = textStateVersion } if len(s.Modules) == 0 { - root := &ModuleState{} + root := &ModuleState{ + Path: rootModulePath, + } root.init() s.Modules = []*ModuleState{root} } diff --git a/terraform/state_test.go b/terraform/state_test.go index 26ae4381c..d11d520dc 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -2,7 +2,11 @@ package terraform import ( "bytes" + "encoding/gob" + "errors" + "io" "reflect" + "sync" "testing" "github.com/hashicorp/terraform/config" @@ -10,10 +14,12 @@ import ( func TestResourceState_MergeDiff(t *testing.T) { rs := ResourceState{ - ID: "foo", - Attributes: map[string]string{ - "foo": "bar", - "port": "8000", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "foo": "bar", + "port": "8000", + }, }, } @@ -46,8 +52,8 @@ func TestResourceState_MergeDiff(t *testing.T) { "baz": config.UnknownVariableValue, } - if !reflect.DeepEqual(expected, rs2.Attributes) { - t.Fatalf("bad: %#v", rs2.Attributes) + if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { + t.Fatalf("bad: %#v", rs2.Primary.Attributes) } } @@ -69,16 +75,18 @@ func TestResourceState_MergeDiff_nil(t *testing.T) { "foo": "baz", } - if !reflect.DeepEqual(expected, rs2.Attributes) { - t.Fatalf("bad: %#v", rs2.Attributes) + if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { + t.Fatalf("bad: %#v", rs2.Primary.Attributes) } } func TestResourceState_MergeDiff_nilDiff(t *testing.T) { rs := ResourceState{ - ID: "foo", - Attributes: map[string]string{ - "foo": "bar", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "foo": "bar", + }, }, } @@ -88,15 +96,15 @@ func TestResourceState_MergeDiff_nilDiff(t *testing.T) { "foo": "bar", } - if !reflect.DeepEqual(expected, rs2.Attributes) { - t.Fatalf("bad: %#v", rs2.Attributes) + if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { + t.Fatalf("bad: %#v", rs2.Primary.Attributes) } } -func TestReadWriteState(t *testing.T) { - state := &State{ - Resources: map[string]*ResourceState{ - "foo": &ResourceState{ +func TestReadWriteStateV1(t *testing.T) { + state := &StateV1{ + Resources: map[string]*ResourceStateV1{ + "foo": &ResourceStateV1{ ID: "bar", ConnInfo: map[string]string{ "type": "ssh", @@ -111,7 +119,7 @@ func TestReadWriteState(t *testing.T) { chksum := checksumStruct(t, state) buf := new(bytes.Buffer) - if err := WriteState(state, buf); err != nil { + if err := testWriteStateV1(state, buf); err != nil { t.Fatalf("err: %s", err) } @@ -121,7 +129,7 @@ func TestReadWriteState(t *testing.T) { t.Fatalf("structure changed during serialization!") } - actual, err := ReadState(buf) + actual, err := ReadStateV1(buf) if err != nil { t.Fatalf("err: %s", err) } @@ -133,3 +141,60 @@ func TestReadWriteState(t *testing.T) { t.Fatalf("bad: %#v", actual) } } + +// sensitiveState is used to store sensitive state information +// that should not be serialized. This is only used temporarily +// and is restored into the state. +type sensitiveState struct { + ConnInfo map[string]map[string]string + + once sync.Once +} + +func (s *sensitiveState) init() { + s.once.Do(func() { + s.ConnInfo = make(map[string]map[string]string) + }) +} + +// testWriteStateV1 writes a state somewhere in a binary format. +// Only for testing now +func testWriteStateV1(d *StateV1, dst io.Writer) error { + // Write the magic bytes so we can determine the file format later + n, err := dst.Write([]byte(stateFormatMagic)) + if err != nil { + return err + } + if n != len(stateFormatMagic) { + return errors.New("failed to write state format magic bytes") + } + + // Write a version byte so we can iterate on version at some point + n, err = dst.Write([]byte{stateFormatVersion}) + if err != nil { + return err + } + if n != 1 { + return errors.New("failed to write state version byte") + } + + // Prevent sensitive information from being serialized + sensitive := &sensitiveState{} + sensitive.init() + for name, r := range d.Resources { + if r.ConnInfo != nil { + sensitive.ConnInfo[name] = r.ConnInfo + r.ConnInfo = nil + } + } + + // Serialize the state + err = gob.NewEncoder(dst).Encode(d) + + // Restore the state + for name, info := range sensitive.ConnInfo { + d.Resources[name].ConnInfo = info + } + + return err +} From 95f3e626a51cd75a8373eeead2a11434133494bd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:20:11 -0700 Subject: [PATCH 14/85] terraform: modify the ResourceProvider API super hardcore --- terraform/context.go | 40 +++++-- terraform/context_test.go | 156 ++++++++++++------------- terraform/resource_provider.go | 17 ++- terraform/resource_provider_mock.go | 39 ++++--- terraform/resource_provisioner.go | 2 +- terraform/resource_provisioner_mock.go | 6 +- terraform/state.go | 76 ++++++------ terraform/state_test.go | 48 ++++---- 8 files changed, 203 insertions(+), 181 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index da4d707cd..e63f26ae4 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -514,7 +514,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return err } - diff, err = r.Provider.Diff(r.State, r.Config) + is := new(InstanceState) // TODO(armon): completely broken + info := new(InstanceInfo) + diff, err = r.Provider.Diff(info, is, r.Config) if err != nil { return err } @@ -557,9 +559,14 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { handleHook(h.PreApply(r.Id, r.State, diff)) } + // TODO(armon): completely broken, added to compile + var rs *ResourceState + is := new(InstanceState) + info := new(InstanceInfo) + // With the completed diff, apply! log.Printf("[DEBUG] %s: Executing Apply", r.Id) - rs, applyerr := r.Provider.Apply(r.State, diff) + is, applyerr := r.Provider.Apply(info, is, diff) var errs []error if applyerr != nil { @@ -614,7 +621,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { handleHook(h.PreProvisionResource(r.Id, r.State)) } - if err := c.applyProvisioners(r, rs); err != nil { + // TODO(armon): I renamed "rs" to "is" to get things to + // compile. + if err := c.applyProvisioners(r, is); err != nil { errs = append(errs, err) tainted = true } @@ -654,11 +663,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // applyProvisioners is used to run any provisioners a resource has // defined after the resource creation has already completed. -func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error { +func (c *Context) applyProvisioners(r *Resource, is *InstanceState) error { // Store the original connection info, restore later - origConnInfo := rs.Primary.Ephemeral.ConnInfo + origConnInfo := is.Ephemeral.ConnInfo defer func() { - rs.Primary.Ephemeral.ConnInfo = origConnInfo + is.Ephemeral.ConnInfo = origConnInfo }() for _, prov := range r.Provisioners { @@ -701,14 +710,14 @@ func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error { overlay[k] = fmt.Sprintf("%v", vt) } } - rs.Primary.Ephemeral.ConnInfo = overlay + is.Ephemeral.ConnInfo = overlay // Invoke the Provisioner for _, h := range c.hooks { handleHook(h.PreProvision(r.Id, prov.Type)) } - if err := prov.Provisioner.Apply(rs, prov.Config); err != nil { + if err := prov.Provisioner.Apply(is, prov.Config); err != nil { return err } @@ -753,7 +762,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { state = new(ResourceState) state.Type = r.State.Type } - diff, err = r.Provider.Diff(state, r.Config) + is := new(InstanceState) // TODO(armon): completely broken + info := new(InstanceInfo) // TODO(armon): completely broken + diff, err = r.Provider.Diff(info, is, r.Config) if err != nil { return err } @@ -797,7 +808,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { // Determine the new state and update variables if !diff.Empty() { - r.State = r.State.MergeDiff(diff) + // TODO(armon): commented to compile, this is important + // but needs to be fixed to work with InstanceState + //r.State = r.State.MergeDiff(diff) } // Update our internal state so that variable computation works @@ -852,7 +865,12 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { handleHook(h.PreRefresh(r.Id, r.State)) } - rs, err := r.Provider.Refresh(r.State) + // TODO(armon): completely broken + var rs *ResourceState + is := new(InstanceState) + info := new(InstanceInfo) + + is, err := r.Provider.Refresh(info, is) if err != nil { return err } diff --git a/terraform/context_test.go b/terraform/context_test.go index fb5bd2f9d..1dbbc7d9b 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -411,7 +411,7 @@ func TestContextApply_badDiff(t *testing.T) { t.Fatalf("err: %s", err) } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "newp": nil, @@ -436,7 +436,7 @@ func TestContextApply_cancel(t *testing.T) { }, }) - p.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) { if !stopped { stopped = true go ctx.Stop() @@ -448,16 +448,14 @@ func TestContextApply_cancel(t *testing.T) { } } - return &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", - }, + return &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", }, }, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ @@ -542,7 +540,7 @@ func TestContextApply_nilDiff(t *testing.T) { t.Fatalf("err: %s", err) } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return nil, nil } @@ -557,7 +555,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) { pr := testProvisioner() p.ApplyFn = testApplyFn p.DiffFn = testDiffFn - pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { val, ok := c.Config["foo"] if !ok || val != "computed_dynamical" { t.Fatalf("bad value for foo: %v %#v", val, c) @@ -606,7 +604,7 @@ func TestContextApply_provisionerFail(t *testing.T) { p.ApplyFn = testApplyFn p.DiffFn = testDiffFn - pr.ApplyFn = func(*ResourceState, *ResourceConfig) error { + pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { return fmt.Errorf("EXPLOSION") } @@ -645,7 +643,7 @@ func TestContextApply_provisionerResourceRef(t *testing.T) { pr := testProvisioner() p.ApplyFn = testApplyFn p.DiffFn = testDiffFn - pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { val, ok := c.Config["foo"] if !ok || val != "2" { t.Fatalf("bad value for foo: %v %#v", val, c) @@ -711,7 +709,7 @@ func TestContextApply_outputDiffVars(t *testing.T) { State: s, }) - p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { for k, ad := range d.Attributes { if ad.NewComputed { return nil, fmt.Errorf("%s: computed", k) @@ -719,10 +717,10 @@ func TestContextApply_outputDiffVars(t *testing.T) { } result := s.MergeDiff(d) - result.Primary.ID = "foo" + result.ID = "foo" return result, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ @@ -749,13 +747,13 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) { p := testProvider("aws") pr := testProvisioner() - p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { - if s.Primary.Ephemeral.ConnInfo == nil { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + if s.Ephemeral.ConnInfo == nil { t.Fatalf("ConnInfo not initialized") } - result, _ := testApplyFn(s, d) - result.Primary.Ephemeral.ConnInfo = map[string]string{ + result, _ := testApplyFn(info, s, d) + result.Ephemeral.ConnInfo = map[string]string{ "type": "ssh", "host": "127.0.0.1", "port": "22", @@ -764,8 +762,8 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) { } p.DiffFn = testDiffFn - pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { - conn := rs.Primary.Ephemeral.ConnInfo + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { + conn := rs.Ephemeral.ConnInfo if conn["type"] != "telnet" { t.Fatalf("Bad: %#v", conn) } @@ -937,16 +935,16 @@ func TestContextApply_destroyOrphan(t *testing.T) { State: s, }) - p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { if d.Destroy { return nil, nil } result := s.MergeDiff(d) - result.Primary.ID = "foo" + result.ID = "foo" return result, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ @@ -983,27 +981,23 @@ func TestContextApply_error(t *testing.T) { }, }) - p.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) { if errored { - state := &ResourceState{ - Primary: &InstanceState{ - ID: "bar", - }, + state := &InstanceState{ + ID: "bar", } return state, fmt.Errorf("error") } errored = true - return &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", - }, + return &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", }, }, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ @@ -1057,22 +1051,20 @@ func TestContextApply_errorPartial(t *testing.T) { State: s, }) - p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { if errored { return s, fmt.Errorf("error") } errored = true - return &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - Attributes: map[string]string{ - "num": "2", - }, + return &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", }, }, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ @@ -1143,16 +1135,16 @@ func TestContextApply_idAttr(t *testing.T) { }, }) - p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { result := s.MergeDiff(d) - result.Primary.ID = "foo" - result.Primary.Attributes = map[string]string{ + result.ID = "foo" + result.Attributes = map[string]string{ "id": "bar", } return result, nil } - p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { return &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ @@ -1762,9 +1754,11 @@ func TestContextPlan_diffVar(t *testing.T) { }) p.DiffFn = func( - s *ResourceState, c *ResourceConfig) (*ResourceDiff, error) { - if s.Primary.ID != "bar" { - return testDiffFn(s, c) + info *InstanceInfo, + s *InstanceState, + c *ResourceConfig) (*ResourceDiff, error) { + if s.ID != "bar" { + return testDiffFn(info, s, c) } return &ResourceDiff{ @@ -1993,10 +1987,8 @@ func TestContextRefresh(t *testing.T) { }) p.RefreshFn = nil - p.RefreshReturn = &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - }, + p.RefreshReturn = &InstanceState{ + ID: "foo", } s, err := ctx.Refresh() @@ -2007,7 +1999,7 @@ func TestContextRefresh(t *testing.T) { if !p.RefreshCalled { t.Fatal("refresh should be called") } - if p.RefreshState.Primary.ID != "foo" { + if p.RefreshState.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { @@ -2072,10 +2064,8 @@ func TestContextRefresh_ignoreUncreated(t *testing.T) { }) p.RefreshFn = nil - p.RefreshReturn = &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - }, + p.RefreshReturn = &InstanceState{ + ID: "foo", } _, err := ctx.Refresh() @@ -2157,10 +2147,8 @@ func TestContextRefresh_state(t *testing.T) { }) p.RefreshFn = nil - p.RefreshReturn = &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - }, + p.RefreshReturn = &InstanceState{ + ID: "foo", } s, err := ctx.Refresh() @@ -2206,10 +2194,8 @@ func TestContextRefresh_vars(t *testing.T) { }) p.RefreshFn = nil - p.RefreshReturn = &ResourceState{ - Primary: &InstanceState{ - ID: "foo", - }, + p.RefreshReturn = &InstanceState{ + ID: "foo", } s, err := ctx.Refresh() @@ -2220,7 +2206,7 @@ func TestContextRefresh_vars(t *testing.T) { if !p.RefreshCalled { t.Fatal("refresh should be called") } - if p.RefreshState.Primary.ID != "foo" { + if p.RefreshState.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { @@ -2239,8 +2225,9 @@ func testContext(t *testing.T, opts *ContextOpts) *Context { } func testApplyFn( - s *ResourceState, - d *ResourceDiff) (*ResourceState, error) { + info *InstanceInfo, + s *InstanceState, + d *ResourceDiff) (*InstanceState, error) { if d.Destroy { return nil, nil } @@ -2250,25 +2237,28 @@ func testApplyFn( id = idAttr.New } - result := &ResourceState{ - Primary: &InstanceState{ - ID: id, - }, + result := &InstanceState{ + ID: id, } if d != nil { result = result.MergeDiff(d) } - if depAttr, ok := d.Attributes["dep"]; ok { - result.Dependencies = []string{depAttr.New} - } + // TODO(armon): commenting this out to compile, but you're in the + // process of removing this, too anyways. Remove when safe. + /* + if depAttr, ok := d.Attributes["dep"]; ok { + result.Dependencies = []string{depAttr.New} + } + */ return result, nil } func testDiffFn( - s *ResourceState, + info *InstanceInfo, + s *InstanceState, c *ResourceConfig) (*ResourceDiff, error) { var diff ResourceDiff diff.Attributes = make(map[string]*ResourceAttrDiff) @@ -2338,7 +2328,7 @@ func testDiffFn( continue } - old, ok := s.Primary.Attributes[k] + old, ok := s.Attributes[k] if !ok { continue } @@ -2350,7 +2340,7 @@ func testDiffFn( if !diff.Empty() { diff.Attributes["type"] = &ResourceAttrDiff{ Old: "", - New: s.Type, + New: info.Type, } } @@ -2359,7 +2349,7 @@ func testDiffFn( func testProvider(prefix string) *MockResourceProvider { p := new(MockResourceProvider) - p.RefreshFn = func(s *ResourceState) (*ResourceState, error) { + p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { return s, nil } p.ResourcesReturn = []ResourceType{ diff --git a/terraform/resource_provider.go b/terraform/resource_provider.go index 39942d8a2..2bdf3c238 100644 --- a/terraform/resource_provider.go +++ b/terraform/resource_provider.go @@ -46,18 +46,27 @@ type ResourceProvider interface { // If the resource state given has an empty ID, then a new resource // is expected to be created. Apply( - *ResourceState, - *ResourceDiff) (*ResourceState, error) + *InstanceInfo, + *InstanceState, + *ResourceDiff) (*InstanceState, error) // Diff diffs a resource versus a desired state and returns // a diff. Diff( - *ResourceState, + *InstanceInfo, + *InstanceState, *ResourceConfig) (*ResourceDiff, error) // Refresh refreshes a resource and updates all of its attributes // with the latest information. - Refresh(*ResourceState) (*ResourceState, error) + Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error) +} + +// InstanceInfo is used to hold information about the instance and/or +// resource being modified. +type InstanceInfo struct { + // Type is the resource type of this instance + Type string } // ResourceType is a type of resource that a resource provider can manage. diff --git a/terraform/resource_provider_mock.go b/terraform/resource_provider_mock.go index 42faada7c..79c946dc2 100644 --- a/terraform/resource_provider_mock.go +++ b/terraform/resource_provider_mock.go @@ -13,24 +13,27 @@ type MockResourceProvider struct { Meta interface{} ApplyCalled bool - ApplyState *ResourceState + ApplyInfo *InstanceInfo + ApplyState *InstanceState ApplyDiff *ResourceDiff - ApplyFn func(*ResourceState, *ResourceDiff) (*ResourceState, error) - ApplyReturn *ResourceState + ApplyFn func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) + ApplyReturn *InstanceState ApplyReturnError error ConfigureCalled bool ConfigureConfig *ResourceConfig ConfigureReturnError error DiffCalled bool - DiffState *ResourceState + DiffInfo *InstanceInfo + DiffState *InstanceState DiffDesired *ResourceConfig - DiffFn func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) + DiffFn func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) DiffReturn *ResourceDiff DiffReturnError error RefreshCalled bool - RefreshState *ResourceState - RefreshFn func(*ResourceState) (*ResourceState, error) - RefreshReturn *ResourceState + RefreshInfo *InstanceInfo + RefreshState *InstanceState + RefreshFn func(*InstanceInfo, *InstanceState) (*InstanceState, error) + RefreshReturn *InstanceState RefreshReturnError error ResourcesCalled bool ResourcesReturn []ResourceType @@ -80,47 +83,53 @@ func (p *MockResourceProvider) Configure(c *ResourceConfig) error { } func (p *MockResourceProvider) Apply( - state *ResourceState, - diff *ResourceDiff) (*ResourceState, error) { + info *InstanceInfo, + state *InstanceState, + diff *ResourceDiff) (*InstanceState, error) { p.Lock() defer p.Unlock() p.ApplyCalled = true + p.ApplyInfo = info p.ApplyState = state p.ApplyDiff = diff if p.ApplyFn != nil { - return p.ApplyFn(state, diff) + return p.ApplyFn(info, state, diff) } return p.ApplyReturn, p.ApplyReturnError } func (p *MockResourceProvider) Diff( - state *ResourceState, + info *InstanceInfo, + state *InstanceState, desired *ResourceConfig) (*ResourceDiff, error) { p.Lock() defer p.Unlock() p.DiffCalled = true + p.DiffInfo = info p.DiffState = state p.DiffDesired = desired if p.DiffFn != nil { - return p.DiffFn(state, desired) + return p.DiffFn(info, state, desired) } return p.DiffReturn, p.DiffReturnError } func (p *MockResourceProvider) Refresh( - s *ResourceState) (*ResourceState, error) { + info *InstanceInfo, + s *InstanceState) (*InstanceState, error) { p.Lock() defer p.Unlock() p.RefreshCalled = true + p.RefreshInfo = info p.RefreshState = s if p.RefreshFn != nil { - return p.RefreshFn(s) + return p.RefreshFn(info, s) } return p.RefreshReturn, p.RefreshReturnError diff --git a/terraform/resource_provisioner.go b/terraform/resource_provisioner.go index 967e0e037..6a749e001 100644 --- a/terraform/resource_provisioner.go +++ b/terraform/resource_provisioner.go @@ -20,7 +20,7 @@ type ResourceProvisioner interface { // resource state along with an error. Instead of a diff, the ResourceConfig // is provided since provisioners only run after a resource has been // newly created. - Apply(*ResourceState, *ResourceConfig) error + Apply(*InstanceState, *ResourceConfig) error } // ResourceProvisionerFactory is a function type that creates a new instance diff --git a/terraform/resource_provisioner_mock.go b/terraform/resource_provisioner_mock.go index a6e62a593..f1600784c 100644 --- a/terraform/resource_provisioner_mock.go +++ b/terraform/resource_provisioner_mock.go @@ -7,9 +7,9 @@ type MockResourceProvisioner struct { Meta interface{} ApplyCalled bool - ApplyState *ResourceState + ApplyState *InstanceState ApplyConfig *ResourceConfig - ApplyFn func(*ResourceState, *ResourceConfig) error + ApplyFn func(*InstanceState, *ResourceConfig) error ApplyReturnError error ValidateCalled bool @@ -28,7 +28,7 @@ func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error return p.ValidateReturnWarns, p.ValidateReturnErrors } -func (p *MockResourceProvisioner) Apply(state *ResourceState, c *ResourceConfig) error { +func (p *MockResourceProvisioner) Apply(state *InstanceState, c *ResourceConfig) error { p.ApplyCalled = true p.ApplyState = state p.ApplyConfig = c diff --git a/terraform/state.go b/terraform/state.go index 69e89bac5..f7b3067f4 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -341,44 +341,6 @@ func (s *ResourceState) GoString() string { return fmt.Sprintf("*%#v", *s) } -// MergeDiff takes a ResourceDiff and merges the attributes into -// this resource state in order to generate a new state. This new -// state can be used to provide updated attribute lookups for -// variable interpolation. -// -// If the diff attribute requires computing the value, and hence -// won't be available until apply, the value is replaced with the -// computeID. -func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { - var result ResourceState - if s != nil { - result = *s - } - result.init() - - if s != nil { - for k, v := range s.Primary.Attributes { - result.Primary.Attributes[k] = v - } - } - if d != nil { - for k, diff := range d.Attributes { - if diff.NewRemoved { - delete(result.Primary.Attributes, k) - continue - } - if diff.NewComputed { - result.Primary.Attributes[k] = config.UnknownVariableValue - continue - } - - result.Primary.Attributes[k] = diff.New - } - } - - return &result -} - // InstanceState is used to track the unique state information belonging // to a given instance. type InstanceState struct { @@ -425,6 +387,44 @@ func (i *InstanceState) deepcopy() *InstanceState { return n } +// MergeDiff takes a ResourceDiff and merges the attributes into +// this resource state in order to generate a new state. This new +// state can be used to provide updated attribute lookups for +// variable interpolation. +// +// If the diff attribute requires computing the value, and hence +// won't be available until apply, the value is replaced with the +// computeID. +func (s *InstanceState) MergeDiff(d *ResourceDiff) *InstanceState { + var result InstanceState + if s != nil { + result = *s + } + result.init() + + if s != nil { + for k, v := range s.Attributes { + result.Attributes[k] = v + } + } + if d != nil { + for k, diff := range d.Attributes { + if diff.NewRemoved { + delete(result.Attributes, k) + continue + } + if diff.NewComputed { + result.Attributes[k] = config.UnknownVariableValue + continue + } + + result.Attributes[k] = diff.New + } + } + + return &result +} + func (i *InstanceState) GoString() string { return fmt.Sprintf("*%#v", *i) } diff --git a/terraform/state_test.go b/terraform/state_test.go index d11d520dc..13f953e3f 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -12,14 +12,12 @@ import ( "github.com/hashicorp/terraform/config" ) -func TestResourceState_MergeDiff(t *testing.T) { - rs := ResourceState{ - Primary: &InstanceState{ - ID: "foo", - Attributes: map[string]string{ - "foo": "bar", - "port": "8000", - }, +func TestInstanceState_MergeDiff(t *testing.T) { + is := InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "foo": "bar", + "port": "8000", }, } @@ -44,7 +42,7 @@ func TestResourceState_MergeDiff(t *testing.T) { }, } - rs2 := rs.MergeDiff(diff) + is2 := is.MergeDiff(diff) expected := map[string]string{ "foo": "baz", @@ -52,13 +50,13 @@ func TestResourceState_MergeDiff(t *testing.T) { "baz": config.UnknownVariableValue, } - if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { - t.Fatalf("bad: %#v", rs2.Primary.Attributes) + if !reflect.DeepEqual(expected, is2.Attributes) { + t.Fatalf("bad: %#v", is2.Attributes) } } -func TestResourceState_MergeDiff_nil(t *testing.T) { - var rs *ResourceState = nil +func TestInstanceState_MergeDiff_nil(t *testing.T) { + var is *InstanceState = nil diff := &ResourceDiff{ Attributes: map[string]*ResourceAttrDiff{ @@ -69,35 +67,33 @@ func TestResourceState_MergeDiff_nil(t *testing.T) { }, } - rs2 := rs.MergeDiff(diff) + is2 := is.MergeDiff(diff) expected := map[string]string{ "foo": "baz", } - if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { - t.Fatalf("bad: %#v", rs2.Primary.Attributes) + if !reflect.DeepEqual(expected, is2.Attributes) { + t.Fatalf("bad: %#v", is2.Attributes) } } -func TestResourceState_MergeDiff_nilDiff(t *testing.T) { - rs := ResourceState{ - Primary: &InstanceState{ - ID: "foo", - Attributes: map[string]string{ - "foo": "bar", - }, +func TestInstanceState_MergeDiff_nilDiff(t *testing.T) { + is := InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "foo": "bar", }, } - rs2 := rs.MergeDiff(nil) + is2 := is.MergeDiff(nil) expected := map[string]string{ "foo": "bar", } - if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { - t.Fatalf("bad: %#v", rs2.Primary.Attributes) + if !reflect.DeepEqual(expected, is2.Attributes) { + t.Fatalf("bad: %#v", is2.Attributes) } } From 25a3cc480cc7105a61ae5eda7e7b723fd2970774 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 16:21:09 -0700 Subject: [PATCH 15/85] terraform: fixing tons of panics --- terraform/context.go | 22 ++++++++++++++++++---- terraform/state.go | 20 +++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index e63f26ae4..d0777142a 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -121,6 +121,10 @@ func (c *Context) Apply() (*State, error) { // Set our state right away. No matter what, this IS our new state, // even if there is an error below. c.state = c.state.deepcopy() + if c.state == nil { + c.state = &State{} + } + c.state.init() // Walk log.Printf("[INFO] Apply walk starting") @@ -190,7 +194,12 @@ func (c *Context) Plan(opts *PlanOpts) (*Plan, error) { // the plan can update a fake state so that variables work, then // we replace it back with our old state. old := c.state - c.state = old.deepcopy() + if old == nil { + c.state = &State{} + c.state.init() + } else { + c.state = old.deepcopy() + } defer func() { c.state = old }() @@ -780,16 +789,21 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { diff.Destroy = true } - if diff.RequiresNew() && r.State.Primary.ID != "" { + if diff.RequiresNew() && r.State.Primary != nil && r.State.Primary.ID != "" { // This will also require a destroy diff.Destroy = true } - if diff.RequiresNew() || r.State.Primary.ID == "" { + if diff.RequiresNew() || r.State.Primary == nil || r.State.Primary.ID == "" { + var oldID string + if r.State.Primary != nil { + oldID = r.State.Primary.Attributes["id"] + } + // Add diff to compute new ID diff.init() diff.Attributes["id"] = &ResourceAttrDiff{ - Old: r.State.Primary.Attributes["id"], + Old: oldID, NewComputed: true, RequiresNew: true, Type: DiffAttrOutput, diff --git a/terraform/state.go b/terraform/state.go index f7b3067f4..2a201a5a7 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -38,6 +38,9 @@ type State struct { // This should be the prefered lookup mechanism as it allows for future // lookup optimizations. func (s *State) ModuleByPath(path []string) *ModuleState { + if s == nil { + return nil + } for _, mod := range s.Modules { if reflect.DeepEqual(mod.Path, path) { return mod @@ -111,7 +114,10 @@ func (s *State) String() string { for _, k := range names { rs := mod.Resources[k] - id := rs.Primary.ID + var id string + if rs.Primary != nil { + id = rs.Primary.ID + } if id == "" { id = "" } @@ -124,8 +130,12 @@ func (s *State) String() string { buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) buf.WriteString(fmt.Sprintf(" ID = %s\n", id)) - attrKeys := make([]string, 0, len(rs.Primary.Attributes)) - for ak, _ := range rs.Primary.Attributes { + var attributes map[string]string + if rs.Primary != nil { + attributes = rs.Primary.Attributes + } + attrKeys := make([]string, 0, len(attributes)) + for ak, _ := range attributes { if ak == "id" { continue } @@ -135,7 +145,7 @@ func (s *State) String() string { sort.Strings(attrKeys) for _, ak := range attrKeys { - av := rs.Primary.Attributes[ak] + av := attributes[ak] buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) } @@ -302,8 +312,8 @@ type ResourceState struct { func (r *ResourceState) init() { if r.Primary == nil { r.Primary = &InstanceState{} - r.Primary.init() } + r.Primary.init() } func (r *ResourceState) deepcopy() *ResourceState { From 585067c8f508a20537b6e66165337b3d0e2862c9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:48:33 -0700 Subject: [PATCH 16/85] rpc: conform to new API --- rpc/resource_provider.go | 43 ++++++++++++++++++++++---------- rpc/resource_provider_test.go | 24 ++++++++++-------- rpc/resource_provisioner.go | 4 +-- rpc/resource_provisioner_test.go | 2 +- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/rpc/resource_provider.go b/rpc/resource_provider.go index 3bbca0d9a..a3f8b243d 100644 --- a/rpc/resource_provider.go +++ b/rpc/resource_provider.go @@ -73,10 +73,12 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { var resp ResourceProviderApplyResponse args := &ResourceProviderApplyArgs{ + Info: info, State: s, Diff: d, } @@ -93,10 +95,12 @@ func (p *ResourceProvider) Apply( } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { var resp ResourceProviderDiffResponse args := &ResourceProviderDiffArgs{ + Info: info, State: s, Config: c, } @@ -112,9 +116,15 @@ func (p *ResourceProvider) Diff( } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { var resp ResourceProviderRefreshResponse - err := p.Client.Call(p.Name+".Refresh", s, &resp) + args := &ResourceProviderRefreshArgs{ + Info: info, + State: s, + } + + err := p.Client.Call(p.Name+".Refresh", args, &resp) if err != nil { return nil, err } @@ -148,17 +158,19 @@ type ResourceProviderConfigureResponse struct { } type ResourceProviderApplyArgs struct { - State *terraform.ResourceState + Info *terraform.InstanceInfo + State *terraform.InstanceState Diff *terraform.ResourceDiff } type ResourceProviderApplyResponse struct { - State *terraform.ResourceState + State *terraform.InstanceState Error *BasicError } type ResourceProviderDiffArgs struct { - State *terraform.ResourceState + Info *terraform.InstanceInfo + State *terraform.InstanceState Config *terraform.ResourceConfig } @@ -167,8 +179,13 @@ type ResourceProviderDiffResponse struct { Error *BasicError } +type ResourceProviderRefreshArgs struct { + Info *terraform.InstanceInfo + State *terraform.InstanceState +} + type ResourceProviderRefreshResponse struct { - State *terraform.ResourceState + State *terraform.InstanceState Error *BasicError } @@ -234,7 +251,7 @@ func (s *ResourceProviderServer) Configure( func (s *ResourceProviderServer) Apply( args *ResourceProviderApplyArgs, result *ResourceProviderApplyResponse) error { - state, err := s.Provider.Apply(args.State, args.Diff) + state, err := s.Provider.Apply(args.Info, args.State, args.Diff) *result = ResourceProviderApplyResponse{ State: state, Error: NewBasicError(err), @@ -245,7 +262,7 @@ func (s *ResourceProviderServer) Apply( func (s *ResourceProviderServer) Diff( args *ResourceProviderDiffArgs, result *ResourceProviderDiffResponse) error { - diff, err := s.Provider.Diff(args.State, args.Config) + diff, err := s.Provider.Diff(args.Info, args.State, args.Config) *result = ResourceProviderDiffResponse{ Diff: diff, Error: NewBasicError(err), @@ -254,9 +271,9 @@ func (s *ResourceProviderServer) Diff( } func (s *ResourceProviderServer) Refresh( - state *terraform.ResourceState, + args *ResourceProviderRefreshArgs, result *ResourceProviderRefreshResponse) error { - newState, err := s.Provider.Refresh(state) + newState, err := s.Provider.Refresh(args.Info, args.State) *result = ResourceProviderRefreshResponse{ State: newState, Error: NewBasicError(err), diff --git a/rpc/resource_provider_test.go b/rpc/resource_provider_test.go index 72e3340e6..e5c6a09f5 100644 --- a/rpc/resource_provider_test.go +++ b/rpc/resource_provider_test.go @@ -101,14 +101,15 @@ func TestResourceProvider_apply(t *testing.T) { } provider := &ResourceProvider{Client: client, Name: name} - p.ApplyReturn = &terraform.ResourceState{ + p.ApplyReturn = &terraform.InstanceState{ ID: "bob", } // Apply - state := &terraform.ResourceState{} + info := &terraform.InstanceInfo{} + state := &terraform.InstanceState{} diff := &terraform.ResourceDiff{} - newState, err := provider.Apply(state, diff) + newState, err := provider.Apply(info, state, diff) if !p.ApplyCalled { t.Fatal("apply should be called") } @@ -142,11 +143,12 @@ func TestResourceProvider_diff(t *testing.T) { } // Diff - state := &terraform.ResourceState{} + info := &terraform.InstanceInfo{} + state := &terraform.InstanceState{} config := &terraform.ResourceConfig{ Raw: map[string]interface{}{"foo": "bar"}, } - diff, err := provider.Diff(state, config) + diff, err := provider.Diff(info, state, config) if !p.DiffCalled { t.Fatal("diff should be called") } @@ -173,11 +175,12 @@ func TestResourceProvider_diff_error(t *testing.T) { p.DiffReturnError = errors.New("foo") // Diff - state := &terraform.ResourceState{} + info := &terraform.InstanceInfo{} + state := &terraform.InstanceState{} config := &terraform.ResourceConfig{ Raw: map[string]interface{}{"foo": "bar"}, } - diff, err := provider.Diff(state, config) + diff, err := provider.Diff(info, state, config) if !p.DiffCalled { t.Fatal("diff should be called") } @@ -201,13 +204,14 @@ func TestResourceProvider_refresh(t *testing.T) { } provider := &ResourceProvider{Client: client, Name: name} - p.RefreshReturn = &terraform.ResourceState{ + p.RefreshReturn = &terraform.InstanceState{ ID: "bob", } // Refresh - state := &terraform.ResourceState{} - newState, err := provider.Refresh(state) + info := &terraform.InstanceInfo{} + state := &terraform.InstanceState{} + newState, err := provider.Refresh(info, state) if !p.RefreshCalled { t.Fatal("refresh should be called") } diff --git a/rpc/resource_provisioner.go b/rpc/resource_provisioner.go index 171cf9f0a..5fc45a98c 100644 --- a/rpc/resource_provisioner.go +++ b/rpc/resource_provisioner.go @@ -36,7 +36,7 @@ func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, [ } func (p *ResourceProvisioner) Apply( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig) error { var resp ResourceProvisionerApplyResponse args := &ResourceProvisionerApplyArgs{ @@ -65,7 +65,7 @@ type ResourceProvisionerValidateResponse struct { } type ResourceProvisionerApplyArgs struct { - State *terraform.ResourceState + State *terraform.InstanceState Config *terraform.ResourceConfig } diff --git a/rpc/resource_provisioner_test.go b/rpc/resource_provisioner_test.go index e31db8dc4..b91252648 100644 --- a/rpc/resource_provisioner_test.go +++ b/rpc/resource_provisioner_test.go @@ -22,7 +22,7 @@ func TestResourceProvisioner_apply(t *testing.T) { provisioner := &ResourceProvisioner{Client: client, Name: name} // Apply - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} conf := &terraform.ResourceConfig{} err = provisioner.Apply(state, conf) if !p.ApplyCalled { From 0de633abeb2be9528a18708a2ad7f4e569e1a7e7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:49:21 -0700 Subject: [PATCH 17/85] plugin: up API version to 2 --- plugin/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/server.go b/plugin/server.go index cc81ffb93..984c1f968 100644 --- a/plugin/server.go +++ b/plugin/server.go @@ -19,7 +19,7 @@ import ( // The APIVersion is outputted along with the RPC address. The plugin // client validates this API version and will show an error if it doesn't // know how to speak it. -const APIVersion = "1" +const APIVersion = "2" // The "magic cookie" is used to verify that the user intended to // actually run this binary. If this cookie isn't present as an From f117e33c9d6f6be2a255e32ebdf4c5a9e893c027 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:55:02 -0700 Subject: [PATCH 18/85] helper/ssh: convert to InstanceState --- helper/ssh/provisioner.go | 10 +++++----- helper/ssh/provisioner_test.go | 30 +++++++++++++++++------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/helper/ssh/provisioner.go b/helper/ssh/provisioner.go index 8affeb7a1..baebbd9b6 100644 --- a/helper/ssh/provisioner.go +++ b/helper/ssh/provisioner.go @@ -43,8 +43,8 @@ type SSHConfig struct { } // VerifySSH is used to verify the ConnInfo is usable by remote-exec -func VerifySSH(s *terraform.ResourceState) error { - connType := s.ConnInfo["type"] +func VerifySSH(s *terraform.InstanceState) error { + connType := s.Ephemeral.ConnInfo["type"] switch connType { case "": case "ssh": @@ -54,9 +54,9 @@ func VerifySSH(s *terraform.ResourceState) error { return nil } -// ParseSSHConfig is used to convert the ConnInfo of the ResourceState into +// ParseSSHConfig is used to convert the ConnInfo of the InstanceState into // a SSHConfig struct -func ParseSSHConfig(s *terraform.ResourceState) (*SSHConfig, error) { +func ParseSSHConfig(s *terraform.InstanceState) (*SSHConfig, error) { sshConf := &SSHConfig{} decConf := &mapstructure.DecoderConfig{ WeaklyTypedInput: true, @@ -66,7 +66,7 @@ func ParseSSHConfig(s *terraform.ResourceState) (*SSHConfig, error) { if err != nil { return nil, err } - if err := dec.Decode(s.ConnInfo); err != nil { + if err := dec.Decode(s.Ephemeral.ConnInfo); err != nil { return nil, err } if sshConf.User == "" { diff --git a/helper/ssh/provisioner_test.go b/helper/ssh/provisioner_test.go index c215e8d29..54f2a5ff6 100644 --- a/helper/ssh/provisioner_test.go +++ b/helper/ssh/provisioner_test.go @@ -7,30 +7,34 @@ import ( ) func TestResourceProvider_verifySSH(t *testing.T) { - r := &terraform.ResourceState{ - ConnInfo: map[string]string{ - "type": "telnet", + r := &terraform.InstanceState{ + Ephemeral: terraform.EphemeralState{ + ConnInfo: map[string]string{ + "type": "telnet", + }, }, } if err := VerifySSH(r); err == nil { t.Fatalf("expected error with telnet") } - r.ConnInfo["type"] = "ssh" + r.Ephemeral.ConnInfo["type"] = "ssh" if err := VerifySSH(r); err != nil { t.Fatalf("err: %v", err) } } func TestResourceProvider_sshConfig(t *testing.T) { - r := &terraform.ResourceState{ - ConnInfo: map[string]string{ - "type": "ssh", - "user": "root", - "password": "supersecret", - "key_file": "/my/key/file.pem", - "host": "127.0.0.1", - "port": "22", - "timeout": "30s", + r := &terraform.InstanceState{ + Ephemeral: terraform.EphemeralState{ + ConnInfo: map[string]string{ + "type": "ssh", + "user": "root", + "password": "supersecret", + "key_file": "/my/key/file.pem", + "host": "127.0.0.1", + "port": "22", + "timeout": "30s", + }, }, } From 81abdcafdc3a293384cfe9064803921285de11cb Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 16:55:10 -0700 Subject: [PATCH 19/85] terraform: fixing all the panics --- terraform/context.go | 21 ++++++++++++++------- terraform/context_test.go | 1 + terraform/graph.go | 12 +++++++----- terraform/state.go | 3 +++ 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index d0777142a..598c63eb1 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -381,8 +381,11 @@ func (c *Context) computeResourceVariable( v.FullKey()) } - attr, ok := r.Primary.Attributes[v.Field] - if ok { + if r.Primary == nil { + goto MISSING + } + + if attr, ok := r.Primary.Attributes[v.Field]; ok { return attr, nil } @@ -390,8 +393,7 @@ func (c *Context) computeResourceVariable( // and see if anything along the way is a computed set. i.e. if // we have "foo.0.bar" as the field, check to see if "foo" is // a computed list. If so, then the whole thing is computed. - parts := strings.Split(v.Field, ".") - if len(parts) > 1 { + if parts := strings.Split(v.Field, "."); len(parts) > 1 { for i := 1; i < len(parts); i++ { key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) if attr, ok := r.Primary.Attributes[key]; ok { @@ -400,6 +402,7 @@ func (c *Context) computeResourceVariable( } } +MISSING: return "", fmt.Errorf( "Resource '%s' does not have attribute '%s' "+ "for variable '%s'", @@ -448,6 +451,10 @@ func (c *Context) computeResourceMultiVariable( continue } + if r.Primary == nil { + continue + } + attr, ok := r.Primary.Attributes[v.Field] if !ok { continue @@ -854,7 +861,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } r := rn.Resource - if r.State.Primary.ID != "" { + if r.State.Primary != nil && r.State.Primary.ID != "" { log.Printf("[DEBUG] %s: Making for destroy", r.Id) l.Lock() @@ -870,7 +877,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { - if r.State.Primary.ID == "" { + if r.State.Primary == nil || r.State.Primary.ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) return nil } @@ -899,7 +906,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { // TODO: Handle other moduels mod := c.state.RootModule() - if rs.Primary.ID == "" { + if len(rs.Tainted) == 0 && (rs.Primary == nil || rs.Primary.ID == "") { delete(mod.Resources, r.Id) } else { mod.Resources[r.Id] = rs diff --git a/terraform/context_test.go b/terraform/context_test.go index 1dbbc7d9b..9c1021711 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1543,6 +1543,7 @@ func TestContextPlan_countDecreaseToOne(t *testing.T) { s := &State{ Modules: []*ModuleState{ &ModuleState{ + Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.foo.0": &ResourceState{ Type: "aws_instance", diff --git a/terraform/graph.go b/terraform/graph.go index ef09fc707..f5e7babd9 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -189,13 +189,12 @@ func graphAddConfigResources( } tainted := false - var mod *ModuleState var state *ResourceState - if s != nil { - // TODO: Handle non-root modules - mod = s.RootModule() + // TODO: Handle non-root modules + mod := s.ModuleByPath(rootModulePath) + if s != nil && mod != nil { // Lookup the resource state state = mod.Resources[name] if state == nil { @@ -511,7 +510,10 @@ func graphAddMissingResourceProviders( // graphAddOrphans adds the orphans to the graph. func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { // TODO: Handle other modules - mod := s.RootModule() + mod := s.ModuleByPath(rootModulePath) + if mod == nil { + return + } for _, k := range mod.Orphans(c) { rs := mod.Resources[k] noun := &depgraph.Noun{ diff --git a/terraform/state.go b/terraform/state.go index 2a201a5a7..0ea366610 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -42,6 +42,9 @@ func (s *State) ModuleByPath(path []string) *ModuleState { return nil } for _, mod := range s.Modules { + if mod.Path == nil { + panic("missing module path") + } if reflect.DeepEqual(mod.Path, path) { return mod } From 90dd00ee3c4e33ce06e885b0323c841124a62e24 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:56:14 -0700 Subject: [PATCH 20/85] helper/diff: InstanceState conversion --- helper/diff/resource_builder.go | 2 +- helper/diff/resource_builder_test.go | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/helper/diff/resource_builder.go b/helper/diff/resource_builder.go index 6f479ed4e..e0516a6d8 100644 --- a/helper/diff/resource_builder.go +++ b/helper/diff/resource_builder.go @@ -61,7 +61,7 @@ type PreProcessFunc func(string) string // Diff returns the ResourceDiff for a resource given its state and // configuration. func (b *ResourceBuilder) Diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { attrs := make(map[string]*terraform.ResourceAttrDiff) diff --git a/helper/diff/resource_builder_test.go b/helper/diff/resource_builder_test.go index c1c4fdd02..e2625b388 100644 --- a/helper/diff/resource_builder_test.go +++ b/helper/diff/resource_builder_test.go @@ -17,7 +17,7 @@ func TestResourceBuilder_attrSetComputed(t *testing.T) { }, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "bar", }, nil) @@ -47,7 +47,7 @@ func TestResourceBuilder_attrSetComputedComplex(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo.#": "0", @@ -75,7 +75,7 @@ func TestResourceBuilder_replaceComputed(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "bar", @@ -99,7 +99,7 @@ func TestResourceBuilder_complex(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "ignore": "1", @@ -138,7 +138,7 @@ func TestResourceBuilder_complexReplace(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "ignore": "1", @@ -180,7 +180,7 @@ func TestResourceBuilder_computedAttrsUpdate(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ Attributes: map[string]string{"foo": "foo"}, } c := testConfig(t, map[string]interface{}{ @@ -210,7 +210,7 @@ func TestResourceBuilder_new(t *testing.T) { ComputedAttrs: []string{"private_ip"}, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "bar", @@ -244,7 +244,7 @@ func TestResourceBuilder_preProcess(t *testing.T) { }, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "foo", }, nil) @@ -283,7 +283,7 @@ func TestResourceBuilder_preProcessUnknown(t *testing.T) { }, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.unknown}", }, map[string]string{ @@ -313,7 +313,7 @@ func TestResourceBuilder_requiresNew(t *testing.T) { }, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "1", Attributes: map[string]string{ "ami": "foo", @@ -345,7 +345,7 @@ func TestResourceBuilder_same(t *testing.T) { ComputedAttrs: []string{"private_ip"}, } - state := &terraform.ResourceState{ + state := &terraform.InstanceState{ ID: "1", Attributes: map[string]string{ "foo": "bar", @@ -372,7 +372,7 @@ func TestResourceBuilder_unknown(t *testing.T) { }, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.unknown}", @@ -403,7 +403,7 @@ func TestResourceBuilder_vars(t *testing.T) { }, } - state := &terraform.ResourceState{} + state := &terraform.InstanceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.foo}", From 0bcbccf046fd2e0a96faa61773f68162b6a222be Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:02:05 -0700 Subject: [PATCH 21/85] helper/resource: compiles, fails because Context doesn't work, probably --- helper/resource/map.go | 29 ++++++++++++++++------------- helper/resource/resource.go | 16 ++++++++-------- helper/resource/testing.go | 12 +++++++++--- helper/resource/testing_test.go | 11 ++++++----- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/helper/resource/map.go b/helper/resource/map.go index 524f33c1c..979791828 100644 --- a/helper/resource/map.go +++ b/helper/resource/map.go @@ -31,12 +31,13 @@ func (m *Map) Validate( // Apply performs a create or update depending on the diff, and calls // the proper function on the matching Resource. func (m *Map) Apply( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { - r, ok := m.Mapping[s.Type] + meta interface{}) (*terraform.InstanceState, error) { + r, ok := m.Mapping[info.Type] if !ok { - return nil, fmt.Errorf("Unknown resource type: %s", s.Type) + return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } if d.Destroy || d.RequiresNew() { @@ -57,7 +58,7 @@ func (m *Map) Apply( } } - var result *terraform.ResourceState + var result *terraform.InstanceState var err error if s.ID == "" { result, err = r.Create(s, d, meta) @@ -65,7 +66,7 @@ func (m *Map) Apply( if r.Update == nil { return s, fmt.Errorf( "Resource type '%s' doesn't support update", - s.Type) + info.Type) } result, err = r.Update(s, d, meta) @@ -83,12 +84,13 @@ func (m *Map) Apply( // Diff performs a diff on the proper resource type. func (m *Map) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { - r, ok := m.Mapping[s.Type] + r, ok := m.Mapping[info.Type] if !ok { - return nil, fmt.Errorf("Unknown resource type: %s", s.Type) + return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } return r.Diff(s, c, meta) @@ -101,16 +103,17 @@ func (m *Map) Diff( // // An error is returned if the resource isn't registered. func (m *Map) Refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + info *terraform.InstanceInfo, + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { // If the resource isn't created, don't refresh. if s.ID == "" { return s, nil } - r, ok := m.Mapping[s.Type] + r, ok := m.Mapping[info.Type] if !ok { - return nil, fmt.Errorf("Unknown resource type: %s", s.Type) + return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } return r.Refresh(s, meta) diff --git a/helper/resource/resource.go b/helper/resource/resource.go index 819ad1769..60a56a31d 100644 --- a/helper/resource/resource.go +++ b/helper/resource/resource.go @@ -17,33 +17,33 @@ type Resource struct { // CreateFunc is a function that creates a resource that didn't previously // exist. type CreateFunc func( - *terraform.ResourceState, + *terraform.InstanceState, *terraform.ResourceDiff, - interface{}) (*terraform.ResourceState, error) + interface{}) (*terraform.InstanceState, error) // DestroyFunc is a function that destroys a resource that previously // exists using the state. type DestroyFunc func( - *terraform.ResourceState, + *terraform.InstanceState, interface{}) error // DiffFunc is a function that performs a diff of a resource. type DiffFunc func( - *terraform.ResourceState, + *terraform.InstanceState, *terraform.ResourceConfig, interface{}) (*terraform.ResourceDiff, error) // RefreshFunc is a function that performs a refresh of a specific type // of resource. type RefreshFunc func( - *terraform.ResourceState, - interface{}) (*terraform.ResourceState, error) + *terraform.InstanceState, + interface{}) (*terraform.InstanceState, error) // UpdateFunc is a function that is called to update a resource that // previously existed. The difference between this and CreateFunc is that // the diff is guaranteed to only contain attributes that don't require // a new resource. type UpdateFunc func( - *terraform.ResourceState, + *terraform.InstanceState, *terraform.ResourceDiff, - interface{}) (*terraform.ResourceState, error) + interface{}) (*terraform.InstanceState, error) diff --git a/helper/resource/testing.go b/helper/resource/testing.go index be09e744d..2b0a2231f 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -244,18 +244,24 @@ func ComposeTestCheckFunc(fs ...TestCheckFunc) TestCheckFunc { func TestCheckResourceAttr(name, key, value string) TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[name] + ms := s.RootModule() + rs, ok := ms.Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } - if rs.Attributes[key] != value { + is := rs.Primary + if is == nil { + return fmt.Errorf("No primary instance: %s", name) + } + + if is.Attributes[key] != value { return fmt.Errorf( "%s: Attribute '%s' expected %#v, got %#v", name, key, value, - rs.Attributes[key]) + is.Attributes[key]) } return nil diff --git a/helper/resource/testing_test.go b/helper/resource/testing_test.go index 7a096149e..ad00f79cc 100644 --- a/helper/resource/testing_test.go +++ b/helper/resource/testing_test.go @@ -18,7 +18,7 @@ func init() { func TestTest(t *testing.T) { mp := testProvider() - mp.ApplyReturn = &terraform.ResourceState{ + mp.ApplyReturn = &terraform.InstanceState{ ID: "foo", } @@ -33,13 +33,14 @@ func TestTest(t *testing.T) { checkStepFn := func(s *terraform.State) error { checkStep = true - rs, ok := s.Resources["test_instance.foo"] + rs, ok := s.RootModule().Resources["test_instance.foo"] if !ok { t.Error("test_instance.foo is not present") return nil } - if rs.ID != "foo" { - t.Errorf("bad check ID: %s", rs.ID) + is := rs.Primary + if is.ID != "foo" { + t.Errorf("bad check ID: %s", is.ID) } return nil @@ -120,7 +121,7 @@ func TestTest_preCheck(t *testing.T) { func TestTest_stepError(t *testing.T) { mp := testProvider() - mp.ApplyReturn = &terraform.ResourceState{ + mp.ApplyReturn = &terraform.InstanceState{ ID: "foo", } From 81d9d70296d573dab18a0461e8342686e102b07e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:07:13 -0700 Subject: [PATCH 22/85] helper/schema: conforms to new API, tests pass --- helper/schema/provider.go | 23 ++--- helper/schema/resource.go | 14 ++-- helper/schema/resource_data.go | 40 +++------ helper/schema/resource_data_test.go | 125 ++++++++++++---------------- helper/schema/resource_test.go | 24 +++--- helper/schema/schema.go | 4 +- helper/schema/schema_test.go | 28 +++---- 7 files changed, 112 insertions(+), 146 deletions(-) diff --git a/helper/schema/provider.go b/helper/schema/provider.go index e59f96494..17f27e8e9 100644 --- a/helper/schema/provider.go +++ b/helper/schema/provider.go @@ -136,11 +136,12 @@ func (p *Provider) Configure(c *terraform.ResourceConfig) error { // Apply implementation of terraform.ResourceProvider interface. func (p *Provider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - r, ok := p.ResourcesMap[s.Type] + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + r, ok := p.ResourcesMap[info.Type] if !ok { - return nil, fmt.Errorf("unknown resource type: %s", s.Type) + return nil, fmt.Errorf("unknown resource type: %s", info.Type) } return r.Apply(s, d, p.meta) @@ -148,11 +149,12 @@ func (p *Provider) Apply( // Diff implementation of terraform.ResourceProvider interface. func (p *Provider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - r, ok := p.ResourcesMap[s.Type] + r, ok := p.ResourcesMap[info.Type] if !ok { - return nil, fmt.Errorf("unknown resource type: %s", s.Type) + return nil, fmt.Errorf("unknown resource type: %s", info.Type) } return r.Diff(s, c) @@ -160,10 +162,11 @@ func (p *Provider) Diff( // Refresh implementation of terraform.ResourceProvider interface. func (p *Provider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - r, ok := p.ResourcesMap[s.Type] + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + r, ok := p.ResourcesMap[info.Type] if !ok { - return nil, fmt.Errorf("unknown resource type: %s", s.Type) + return nil, fmt.Errorf("unknown resource type: %s", info.Type) } return r.Refresh(s, p.meta) diff --git a/helper/schema/resource.go b/helper/schema/resource.go index 480b1e547..e9661c454 100644 --- a/helper/schema/resource.go +++ b/helper/schema/resource.go @@ -61,9 +61,9 @@ type DeleteFunc func(*ResourceData, interface{}) error // Apply creates, updates, and/or deletes a resource. func (r *Resource) Apply( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { data, err := schemaMap(r.Schema).Data(s, d) if err != nil { return s, err @@ -72,7 +72,7 @@ func (r *Resource) Apply( if s == nil { // The Terraform API dictates that this should never happen, but // it doesn't hurt to be safe in this case. - s = new(terraform.ResourceState) + s = new(terraform.InstanceState) } if d.Destroy || d.RequiresNew() { @@ -99,7 +99,7 @@ func (r *Resource) Apply( err = r.Create(data, meta) } else { if r.Update == nil { - return s, fmt.Errorf("%s doesn't support update", s.Type) + return s, fmt.Errorf("doesn't support update") } err = r.Update(data, meta) @@ -111,7 +111,7 @@ func (r *Resource) Apply( // Diff returns a diff of this resource and is API compatible with the // ResourceProvider interface. func (r *Resource) Diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { return schemaMap(r.Schema).Diff(s, c) } @@ -123,8 +123,8 @@ func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) { // Refresh refreshes the state of the resource. func (r *Resource) Refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { data, err := schemaMap(r.Schema).Data(s, nil) if err != nil { return s, err diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index 8f8f600f5..5fbb0d4ea 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -23,13 +23,13 @@ type ResourceData struct { // Settable (internally) schema map[string]*Schema config *terraform.ResourceConfig - state *terraform.ResourceState + state *terraform.InstanceState diff *terraform.ResourceDiff diffing bool // Don't set setMap map[string]string - newState *terraform.ResourceState + newState *terraform.InstanceState partial bool partialMap map[string]struct{} once sync.Once @@ -168,24 +168,11 @@ func (d *ResourceData) Id() string { // ConnInfo returns the connection info for this resource. func (d *ResourceData) ConnInfo() map[string]string { if d.newState != nil { - return d.newState.ConnInfo + return d.newState.Ephemeral.ConnInfo } if d.state != nil { - return d.state.ConnInfo - } - - return nil -} - -// Dependencies returns the dependencies in this state. -func (d *ResourceData) Dependencies() []terraform.ResourceDependency { - if d.newState != nil { - return d.newState.Dependencies - } - - if d.state != nil { - return d.state.Dependencies + return d.state.Ephemeral.ConnInfo } return nil @@ -201,19 +188,13 @@ func (d *ResourceData) SetId(v string) { // SetConnInfo sets the connection info for a resource. func (d *ResourceData) SetConnInfo(v map[string]string) { d.once.Do(d.init) - d.newState.ConnInfo = v + d.newState.Ephemeral.ConnInfo = v } -// SetDependencies sets the dependencies of a resource. -func (d *ResourceData) SetDependencies(ds []terraform.ResourceDependency) { - d.once.Do(d.init) - d.newState.Dependencies = ds -} - -// State returns the new ResourceState after the diff and any Set +// State returns the new InstanceState after the diff and any Set // calls. -func (d *ResourceData) State() *terraform.ResourceState { - var result terraform.ResourceState +func (d *ResourceData) State() *terraform.InstanceState { + var result terraform.InstanceState result.ID = d.Id() // If we have no ID, then this resource doesn't exist and we just @@ -223,8 +204,7 @@ func (d *ResourceData) State() *terraform.ResourceState { } result.Attributes = d.stateObject("", d.schema) - result.ConnInfo = d.ConnInfo() - result.Dependencies = d.Dependencies() + result.Ephemeral.ConnInfo = d.ConnInfo() if v := d.Id(); v != "" { result.Attributes["id"] = d.Id() @@ -234,7 +214,7 @@ func (d *ResourceData) State() *terraform.ResourceState { } func (d *ResourceData) init() { - var copyState terraform.ResourceState + var copyState terraform.InstanceState if d.state != nil { copyState = *d.state } diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index 7f08e4c16..66397dd6a 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -10,7 +10,7 @@ import ( func TestResourceDataGet(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Key string Value interface{} @@ -104,7 +104,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", }, @@ -127,7 +127,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -157,7 +157,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "port": "80", }, @@ -179,7 +179,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", @@ -202,7 +202,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", @@ -241,7 +241,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", @@ -342,7 +342,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -440,7 +440,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "2", "config_vars.0.foo": "baz", @@ -475,7 +475,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.FOO": "bar", @@ -514,7 +514,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "1", "ports.0": "80", @@ -549,7 +549,7 @@ func TestResourceDataGet(t *testing.T) { func TestResourceDataGetChange(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Key string OldValue interface{} @@ -593,7 +593,7 @@ func TestResourceDataGetChange(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -635,7 +635,7 @@ func TestResourceDataGetChange(t *testing.T) { func TestResourceDataGetOk(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Key string Value interface{} @@ -798,7 +798,7 @@ func TestResourceDataGetOk(t *testing.T) { func TestResourceDataHasChange(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Key string Change bool @@ -840,7 +840,7 @@ func TestResourceDataHasChange(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -878,7 +878,7 @@ func TestResourceDataHasChange(t *testing.T) { func TestResourceDataSet(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Key string Value interface{} @@ -1002,7 +1002,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", @@ -1079,7 +1079,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "2", "ingress.0.from": "80", @@ -1119,7 +1119,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "2", "ingress.0.from": "80", @@ -1164,7 +1164,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "2", "ingress.0.from": "80", @@ -1288,7 +1288,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "100", @@ -1318,7 +1318,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "100", @@ -1353,7 +1353,7 @@ func TestResourceDataSet(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "100", @@ -1394,10 +1394,10 @@ func TestResourceDataSet(t *testing.T) { func TestResourceDataState(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Diff *terraform.ResourceDiff Set map[string]interface{} - Result *terraform.ResourceState + Result *terraform.InstanceState Partial []string }{ // Basic primitive in diff @@ -1423,7 +1423,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -1457,7 +1457,7 @@ func TestResourceDataState(t *testing.T) { "availability_zone": "bar", }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", }, @@ -1480,7 +1480,7 @@ func TestResourceDataState(t *testing.T) { "vpc": true, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "vpc": "true", }, @@ -1510,7 +1510,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, @@ -1527,7 +1527,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "1", "ports.0": "80", @@ -1547,7 +1547,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "80", @@ -1573,7 +1573,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "1", "ingress.0.from": "80", @@ -1597,7 +1597,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "2", "ingress.0.from": "150", @@ -1619,7 +1619,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "2", "config_vars.0.foo": "bar", @@ -1642,7 +1642,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "2", "config_vars.0.foo": "bar", @@ -1664,7 +1664,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.FOO": "bar", @@ -1684,7 +1684,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{}, }, }, @@ -1700,7 +1700,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", @@ -1717,7 +1717,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", @@ -1740,7 +1740,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "100", @@ -1751,7 +1751,7 @@ func TestResourceDataState(t *testing.T) { Diff: nil, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "80", @@ -1789,7 +1789,7 @@ func TestResourceDataState(t *testing.T) { Partial: []string{}, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{}, }, }, @@ -1804,7 +1804,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "1", "ports.0": "80", @@ -1826,7 +1826,7 @@ func TestResourceDataState(t *testing.T) { Partial: []string{}, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "1", "ports.0": "80", @@ -1851,7 +1851,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "1", "ingress.0.from": "80", @@ -1877,7 +1877,7 @@ func TestResourceDataState(t *testing.T) { Partial: []string{}, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "1", "ingress.0.from": "80", @@ -1898,7 +1898,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "2", "config_vars.0.foo": "bar", @@ -1923,7 +1923,7 @@ func TestResourceDataState(t *testing.T) { Partial: []string{}, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "2", "config_vars.0.foo": "bar", @@ -1947,7 +1947,7 @@ func TestResourceDataState(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "100", @@ -1966,7 +1966,7 @@ func TestResourceDataState(t *testing.T) { Partial: []string{}, - Result: &terraform.ResourceState{ + Result: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "80", @@ -2029,24 +2029,7 @@ func TestResourceDataSetConnInfo(t *testing.T) { } actual := d.State() - if !reflect.DeepEqual(actual.ConnInfo, expected) { - t.Fatalf("bad: %#v", actual) - } -} - -func TestResourceDataSetDependencies(t *testing.T) { - d := &ResourceData{} - d.SetId("foo") - d.SetDependencies([]terraform.ResourceDependency{ - terraform.ResourceDependency{ID: "foo"}, - }) - - expected := []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: "foo"}, - } - - actual := d.State() - if !reflect.DeepEqual(actual.Dependencies, expected) { + if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) { t.Fatalf("bad: %#v", actual) } } @@ -2063,7 +2046,7 @@ func TestResourceDataSetId(t *testing.T) { func TestResourceDataSetId_clear(t *testing.T) { d := &ResourceData{ - state: &terraform.ResourceState{ID: "bar"}, + state: &terraform.InstanceState{ID: "bar"}, } d.SetId("") @@ -2075,7 +2058,7 @@ func TestResourceDataSetId_clear(t *testing.T) { func TestResourceDataSetId_override(t *testing.T) { d := &ResourceData{ - state: &terraform.ResourceState{ID: "bar"}, + state: &terraform.InstanceState{ID: "bar"}, } d.SetId("foo") diff --git a/helper/schema/resource_test.go b/helper/schema/resource_test.go index 4ca01f7db..ad4ba5fb6 100644 --- a/helper/schema/resource_test.go +++ b/helper/schema/resource_test.go @@ -25,7 +25,7 @@ func TestResourceApply_create(t *testing.T) { return nil } - var s *terraform.ResourceState = nil + var s *terraform.InstanceState = nil d := &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ @@ -44,7 +44,7 @@ func TestResourceApply_create(t *testing.T) { t.Fatal("not called") } - expected := &terraform.ResourceState{ + expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "id": "foo", @@ -73,7 +73,7 @@ func TestResourceApply_destroy(t *testing.T) { return nil } - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "bar", } @@ -110,7 +110,7 @@ func TestResourceApply_destroyPartial(t *testing.T) { return fmt.Errorf("some error") } - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", @@ -126,7 +126,7 @@ func TestResourceApply_destroyPartial(t *testing.T) { t.Fatal("should error") } - expected := &terraform.ResourceState{ + expected := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", @@ -154,7 +154,7 @@ func TestResourceApply_update(t *testing.T) { return nil } - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", @@ -174,7 +174,7 @@ func TestResourceApply_update(t *testing.T) { t.Fatalf("err: %s", err) } - expected := &terraform.ResourceState{ + expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "id": "foo", @@ -199,7 +199,7 @@ func TestResourceApply_updateNoCallback(t *testing.T) { r.Update = nil - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", @@ -219,7 +219,7 @@ func TestResourceApply_updateNoCallback(t *testing.T) { t.Fatal("should error") } - expected := &terraform.ResourceState{ + expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", @@ -282,14 +282,14 @@ func TestResourceRefresh(t *testing.T) { return d.Set("foo", d.Get("foo").(int)+1) } - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } - expected := &terraform.ResourceState{ + expected := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", @@ -322,7 +322,7 @@ func TestResourceRefresh_delete(t *testing.T) { return nil } - s := &terraform.ResourceState{ + s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", diff --git a/helper/schema/schema.go b/helper/schema/schema.go index d1d96e9ac..39d622d22 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -162,7 +162,7 @@ type schemaMap map[string]*Schema // // The diff is optional. func (m schemaMap) Data( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff) (*ResourceData, error) { return &ResourceData{ schema: m, @@ -174,7 +174,7 @@ func (m schemaMap) Data( // Diff returns the diff for a resource given the schema map, // state, and configuration. func (m schemaMap) Diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { result := new(terraform.ResourceDiff) result.Attributes = make(map[string]*terraform.ResourceAttrDiff) diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 6bd70649b..66e812055 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -11,7 +11,7 @@ import ( func TestSchemaMap_Diff(t *testing.T) { cases := []struct { Schema map[string]*Schema - State *terraform.ResourceState + State *terraform.InstanceState Config map[string]interface{} ConfigVariables map[string]string Diff *terraform.ResourceDiff @@ -87,7 +87,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ ID: "foo", }, @@ -394,7 +394,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", @@ -421,7 +421,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "1", @@ -577,7 +577,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "2", @@ -617,7 +617,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "2", @@ -658,7 +658,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", @@ -737,7 +737,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", @@ -767,7 +767,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "port": "80", }, @@ -803,7 +803,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", @@ -843,7 +843,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", @@ -882,7 +882,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", @@ -931,7 +931,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "address": "foo", @@ -979,7 +979,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - State: &terraform.ResourceState{ + State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", From c452579512de733d5988b98802f238eda17007a3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:08:27 -0700 Subject: [PATCH 23/85] provisioners/*: compiling, tests passing --- builtin/provisioners/file/resource_provisioner.go | 2 +- builtin/provisioners/local-exec/resource_provisioner.go | 2 +- builtin/provisioners/remote-exec/resource_provisioner.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/provisioners/file/resource_provisioner.go b/builtin/provisioners/file/resource_provisioner.go index c81721e8d..91970b215 100644 --- a/builtin/provisioners/file/resource_provisioner.go +++ b/builtin/provisioners/file/resource_provisioner.go @@ -13,7 +13,7 @@ import ( type ResourceProvisioner struct{} -func (p *ResourceProvisioner) Apply(s *terraform.ResourceState, +func (p *ResourceProvisioner) Apply(s *terraform.InstanceState, c *terraform.ResourceConfig) error { // Ensure the connection type is SSH if err := helper.VerifySSH(s); err != nil { diff --git a/builtin/provisioners/local-exec/resource_provisioner.go b/builtin/provisioners/local-exec/resource_provisioner.go index 4c756d1d1..234b8ee3e 100644 --- a/builtin/provisioners/local-exec/resource_provisioner.go +++ b/builtin/provisioners/local-exec/resource_provisioner.go @@ -20,7 +20,7 @@ const ( type ResourceProvisioner struct{} func (p *ResourceProvisioner) Apply( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig) error { // Get the command diff --git a/builtin/provisioners/remote-exec/resource_provisioner.go b/builtin/provisioners/remote-exec/resource_provisioner.go index 9c5a162e5..fc694d8aa 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner.go +++ b/builtin/provisioners/remote-exec/resource_provisioner.go @@ -22,7 +22,7 @@ const ( type ResourceProvisioner struct{} -func (p *ResourceProvisioner) Apply(s *terraform.ResourceState, +func (p *ResourceProvisioner) Apply(s *terraform.InstanceState, c *terraform.ResourceConfig) error { // Ensure the connection type is SSH if err := helper.VerifySSH(s); err != nil { From 55f4e35586a62efac2abc09039c22ccc212bfb0d Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 17:10:34 -0700 Subject: [PATCH 24/85] terraform: Fixing applyWalkFn --- terraform/context.go | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 598c63eb1..45aeab386 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -530,9 +530,10 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return err } - is := new(InstanceState) // TODO(armon): completely broken - info := new(InstanceInfo) - diff, err = r.Provider.Diff(info, is, r.Config) + info := &InstanceInfo{ + Type: r.State.Type, + } + diff, err = r.Provider.Diff(info, r.State.Primary, r.Config) if err != nil { return err } @@ -575,14 +576,10 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { handleHook(h.PreApply(r.Id, r.State, diff)) } - // TODO(armon): completely broken, added to compile - var rs *ResourceState - is := new(InstanceState) - info := new(InstanceInfo) - // With the completed diff, apply! log.Printf("[DEBUG] %s: Executing Apply", r.Id) - is, applyerr := r.Provider.Apply(info, is, diff) + info := &InstanceInfo{Type: r.State.Type} + is, applyerr := r.Provider.Apply(info, r.State.Primary, diff) var errs []error if applyerr != nil { @@ -590,38 +587,38 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } // Make sure the result is instantiated - if rs == nil { - rs = new(ResourceState) - rs.init() + if is == nil { + is = new(InstanceState) + is.init() } - // Force the resource state type to be our type - rs.Type = r.State.Type - // Force the "id" attribute to be our ID - if rs.Primary.ID != "" { - rs.Primary.Attributes["id"] = rs.Primary.ID + if is.ID != "" { + is.Attributes["id"] = is.ID } - for ak, av := range rs.Primary.Attributes { + for ak, av := range is.Attributes { // If the value is the unknown variable value, then it is an error. // In this case we record the error and remove it from the state if av == config.UnknownVariableValue { errs = append(errs, fmt.Errorf( "Attribute with unknown value: %s", ak)) - delete(rs.Primary.Attributes, ak) + delete(is.Attributes, ak) } } + // Update the primary instance + r.State.Primary = is + // Update the resulting diff c.sl.Lock() // TODO: Get other modules mod := c.state.RootModule() - if rs.Primary.ID == "" && len(rs.Tainted) == 0 { + if is.ID == "" && len(r.State.Tainted) == 0 { delete(mod.Resources, r.Id) } else { - mod.Resources[r.Id] = rs + mod.Resources[r.Id] = r.State } c.sl.Unlock() @@ -652,13 +649,12 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { c.sl.Lock() if tainted { log.Printf("[DEBUG] %s: Marking as tainted", r.Id) - rs.Tainted = append(rs.Tainted, rs.Primary) - rs.Primary = nil + r.State.Tainted = append(r.State.Tainted, r.State.Primary) + r.State.Primary = nil } c.sl.Unlock() // Update the state for the resource itself - r.State = rs r.Tainted = tainted for _, h := range c.hooks { From ecc10616ba1799790b68f25bdf5a80b376108c49 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:16:53 -0700 Subject: [PATCH 25/85] providers/google: tests passing, compiling --- .../google/resource_compute_address_test.go | 12 ++++++------ .../providers/google/resource_compute_disk_test.go | 12 ++++++------ .../google/resource_compute_firewall_test.go | 12 ++++++------ .../google/resource_compute_instance_test.go | 12 ++++++------ .../google/resource_compute_network_test.go | 12 ++++++------ .../providers/google/resource_compute_route_test.go | 12 ++++++------ 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/builtin/providers/google/resource_compute_address_test.go b/builtin/providers/google/resource_compute_address_test.go index e0c576aee..ba87169d6 100644 --- a/builtin/providers/google/resource_compute_address_test.go +++ b/builtin/providers/google/resource_compute_address_test.go @@ -31,13 +31,13 @@ func TestAccComputeAddress_basic(t *testing.T) { func testAccCheckComputeAddressDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_address" { continue } _, err := config.clientCompute.Addresses.Get( - config.Project, config.Region, rs.ID).Do() + config.Project, config.Region, rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Address still exists") } @@ -48,24 +48,24 @@ func testAccCheckComputeAddressDestroy(s *terraform.State) error { func testAccCheckComputeAddressExists(n string, addr *compute.Address) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Addresses.Get( - config.Project, config.Region, rs.ID).Do() + config.Project, config.Region, rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Addr not found") } diff --git a/builtin/providers/google/resource_compute_disk_test.go b/builtin/providers/google/resource_compute_disk_test.go index 188741fa6..04853e4e8 100644 --- a/builtin/providers/google/resource_compute_disk_test.go +++ b/builtin/providers/google/resource_compute_disk_test.go @@ -31,13 +31,13 @@ func TestAccComputeDisk_basic(t *testing.T) { func testAccCheckComputeDiskDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_disk" { continue } _, err := config.clientCompute.Disks.Get( - config.Project, rs.Attributes["zone"], rs.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Disk still exists") } @@ -48,24 +48,24 @@ func testAccCheckComputeDiskDestroy(s *terraform.State) error { func testAccCheckComputeDiskExists(n string, disk *compute.Disk) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Disks.Get( - config.Project, rs.Attributes["zone"], rs.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Disk not found") } diff --git a/builtin/providers/google/resource_compute_firewall_test.go b/builtin/providers/google/resource_compute_firewall_test.go index a801bd86b..58a6fd787 100644 --- a/builtin/providers/google/resource_compute_firewall_test.go +++ b/builtin/providers/google/resource_compute_firewall_test.go @@ -59,13 +59,13 @@ func TestAccComputeFirewall_update(t *testing.T) { func testAccCheckComputeFirewallDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_firewall" { continue } _, err := config.clientCompute.Firewalls.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Firewall still exists") } @@ -76,24 +76,24 @@ func testAccCheckComputeFirewallDestroy(s *terraform.State) error { func testAccCheckComputeFirewallExists(n string, firewall *compute.Firewall) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Firewalls.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Firewall not found") } diff --git a/builtin/providers/google/resource_compute_instance_test.go b/builtin/providers/google/resource_compute_instance_test.go index af996763e..8759cf94f 100644 --- a/builtin/providers/google/resource_compute_instance_test.go +++ b/builtin/providers/google/resource_compute_instance_test.go @@ -106,13 +106,13 @@ func TestAccComputeInstance_update(t *testing.T) { func testAccCheckComputeInstanceDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_instance" { continue } _, err := config.clientCompute.Instances.Get( - config.Project, rs.Attributes["zone"], rs.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Instance still exists") } @@ -123,24 +123,24 @@ func testAccCheckComputeInstanceDestroy(s *terraform.State) error { func testAccCheckComputeInstanceExists(n string, instance *compute.Instance) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Instances.Get( - config.Project, rs.Attributes["zone"], rs.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Instance not found") } diff --git a/builtin/providers/google/resource_compute_network_test.go b/builtin/providers/google/resource_compute_network_test.go index 60c278117..ea25b0ff4 100644 --- a/builtin/providers/google/resource_compute_network_test.go +++ b/builtin/providers/google/resource_compute_network_test.go @@ -31,13 +31,13 @@ func TestAccComputeNetwork_basic(t *testing.T) { func testAccCheckComputeNetworkDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_network" { continue } _, err := config.clientCompute.Networks.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Network still exists") } @@ -48,24 +48,24 @@ func testAccCheckComputeNetworkDestroy(s *terraform.State) error { func testAccCheckComputeNetworkExists(n string, network *compute.Network) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Networks.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Network not found") } diff --git a/builtin/providers/google/resource_compute_route_test.go b/builtin/providers/google/resource_compute_route_test.go index eb0721d96..065842f85 100644 --- a/builtin/providers/google/resource_compute_route_test.go +++ b/builtin/providers/google/resource_compute_route_test.go @@ -31,13 +31,13 @@ func TestAccComputeRoute_basic(t *testing.T) { func testAccCheckComputeRouteDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_route" { continue } _, err := config.clientCompute.Routes.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err == nil { return fmt.Errorf("Route still exists") } @@ -48,24 +48,24 @@ func testAccCheckComputeRouteDestroy(s *terraform.State) error { func testAccCheckComputeRouteExists(n string, route *compute.Route) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.Routes.Get( - config.Project, rs.ID).Do() + config.Project, rs.Primary.ID).Do() if err != nil { return err } - if found.Name != rs.ID { + if found.Name != rs.Primary.ID { return fmt.Errorf("Route not found") } From 4a736b0dac6f49d07099cdee206c456953480b1f Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 17:19:28 -0700 Subject: [PATCH 26/85] terraform: Fixing panics and TODOs --- terraform/context.go | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 45aeab386..3fd26ce56 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -589,8 +589,8 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // Make sure the result is instantiated if is == nil { is = new(InstanceState) - is.init() } + is.init() // Force the "id" attribute to be our ID if is.ID != "" { @@ -634,8 +634,6 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { handleHook(h.PreProvisionResource(r.Id, r.State)) } - // TODO(armon): I renamed "rs" to "is" to get things to - // compile. if err := c.applyProvisioners(r, is); err != nil { errs = append(errs, err) tainted = true @@ -774,9 +772,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { state = new(ResourceState) state.Type = r.State.Type } - is := new(InstanceState) // TODO(armon): completely broken - info := new(InstanceInfo) // TODO(armon): completely broken - diff, err = r.Provider.Diff(info, is, r.Config) + state.init() + info := &InstanceInfo{Type: state.Type} + diff, err = r.Provider.Diff(info, state.Primary, r.Config) if err != nil { return err } @@ -825,9 +823,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { // Determine the new state and update variables if !diff.Empty() { - // TODO(armon): commented to compile, this is important - // but needs to be fixed to work with InstanceState - //r.State = r.State.MergeDiff(diff) + r.State.Primary = r.State.Primary.MergeDiff(diff) } // Update our internal state so that variable computation works @@ -882,35 +878,29 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { handleHook(h.PreRefresh(r.Id, r.State)) } - // TODO(armon): completely broken - var rs *ResourceState - is := new(InstanceState) - info := new(InstanceInfo) - - is, err := r.Provider.Refresh(info, is) + info := &InstanceInfo{Type: r.State.Type} + is, err := r.Provider.Refresh(info, r.State.Primary) if err != nil { return err } - if rs == nil { - rs = new(ResourceState) + if is == nil { + is = new(InstanceState) + is.init() } - // Fix the type to be the type we have - rs.Type = r.State.Type - c.sl.Lock() // TODO: Handle other moduels mod := c.state.RootModule() - if len(rs.Tainted) == 0 && (rs.Primary == nil || rs.Primary.ID == "") { + if len(r.State.Tainted) == 0 && (r.State.Primary == nil || r.State.Primary.ID == "") { delete(mod.Resources, r.Id) } else { - mod.Resources[r.Id] = rs + mod.Resources[r.Id] = r.State } c.sl.Unlock() for _, h := range c.hooks { - handleHook(h.PostRefresh(r.Id, rs)) + handleHook(h.PostRefresh(r.Id, r.State)) } return nil From 64bc356f978b45715f12581ccb26e710b2a4006f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:20:47 -0700 Subject: [PATCH 27/85] providers/heroku: tests passing, compiling --- builtin/providers/heroku/resource_heroku_addon.go | 4 ---- .../providers/heroku/resource_heroku_addon_test.go | 12 ++++++------ builtin/providers/heroku/resource_heroku_app_test.go | 12 ++++++------ builtin/providers/heroku/resource_heroku_domain.go | 4 ---- .../providers/heroku/resource_heroku_domain_test.go | 12 ++++++------ builtin/providers/heroku/resource_heroku_drain.go | 4 ---- .../providers/heroku/resource_heroku_drain_test.go | 12 ++++++------ 7 files changed, 24 insertions(+), 36 deletions(-) diff --git a/builtin/providers/heroku/resource_heroku_addon.go b/builtin/providers/heroku/resource_heroku_addon.go index b2c36bdf9..3da39e2a3 100644 --- a/builtin/providers/heroku/resource_heroku_addon.go +++ b/builtin/providers/heroku/resource_heroku_addon.go @@ -8,7 +8,6 @@ import ( "github.com/cyberdelia/heroku-go/v3" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" ) // Global lock to prevent parallelism for heroku_addon since @@ -116,9 +115,6 @@ func resourceHerokuAddonRead(d *schema.ResourceData, meta interface{}) error { d.Set("plan", plan) d.Set("provider_id", addon.ProviderID) d.Set("config_vars", []interface{}{addon.ConfigVars}) - d.SetDependencies([]terraform.ResourceDependency{ - terraform.ResourceDependency{ID: d.Get("app").(string)}, - }) return nil } diff --git a/builtin/providers/heroku/resource_heroku_addon_test.go b/builtin/providers/heroku/resource_heroku_addon_test.go index 77363d70b..b4c360e51 100644 --- a/builtin/providers/heroku/resource_heroku_addon_test.go +++ b/builtin/providers/heroku/resource_heroku_addon_test.go @@ -72,12 +72,12 @@ func TestAccHerokuAddon_noPlan(t *testing.T) { func testAccCheckHerokuAddonDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*heroku.Service) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "heroku_addon" { continue } - _, err := client.AddonInfo(rs.Attributes["app"], rs.ID) + _, err := client.AddonInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err == nil { return fmt.Errorf("Addon still exists") @@ -100,25 +100,25 @@ func testAccCheckHerokuAddonAttributes(addon *heroku.Addon, n string) resource.T func testAccCheckHerokuAddonExists(n string, addon *heroku.Addon) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Addon ID is set") } client := testAccProvider.Meta().(*heroku.Service) - foundAddon, err := client.AddonInfo(rs.Attributes["app"], rs.ID) + foundAddon, err := client.AddonInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err != nil { return err } - if foundAddon.ID != rs.ID { + if foundAddon.ID != rs.Primary.ID { return fmt.Errorf("Addon not found") } diff --git a/builtin/providers/heroku/resource_heroku_app_test.go b/builtin/providers/heroku/resource_heroku_app_test.go index 42841cb89..05162ee44 100644 --- a/builtin/providers/heroku/resource_heroku_app_test.go +++ b/builtin/providers/heroku/resource_heroku_app_test.go @@ -105,12 +105,12 @@ func TestAccHerokuApp_NukeVars(t *testing.T) { func testAccCheckHerokuAppDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*heroku.Service) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "heroku_app" { continue } - _, err := client.AppInfo(rs.ID) + _, err := client.AppInfo(rs.Primary.ID) if err == nil { return fmt.Errorf("App still exists") @@ -199,25 +199,25 @@ func testAccCheckHerokuAppAttributesNoVars(app *heroku.App) resource.TestCheckFu func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No App Name is set") } client := testAccProvider.Meta().(*heroku.Service) - foundApp, err := client.AppInfo(rs.ID) + foundApp, err := client.AppInfo(rs.Primary.ID) if err != nil { return err } - if foundApp.Name != rs.ID { + if foundApp.Name != rs.Primary.ID { return fmt.Errorf("App not found") } diff --git a/builtin/providers/heroku/resource_heroku_domain.go b/builtin/providers/heroku/resource_heroku_domain.go index f70c7c5cc..b3c1de79f 100644 --- a/builtin/providers/heroku/resource_heroku_domain.go +++ b/builtin/providers/heroku/resource_heroku_domain.go @@ -6,7 +6,6 @@ import ( "github.com/cyberdelia/heroku-go/v3" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" ) func resourceHerokuDomain() *schema.Resource { @@ -52,9 +51,6 @@ func resourceHerokuDomainCreate(d *schema.ResourceData, meta interface{}) error d.SetId(do.ID) d.Set("hostname", do.Hostname) d.Set("cname", fmt.Sprintf("%s.herokuapp.com", app)) - d.SetDependencies([]terraform.ResourceDependency{ - terraform.ResourceDependency{ID: app}, - }) log.Printf("[INFO] Domain ID: %s", d.Id()) return nil diff --git a/builtin/providers/heroku/resource_heroku_domain_test.go b/builtin/providers/heroku/resource_heroku_domain_test.go index e370e0646..344be24ca 100644 --- a/builtin/providers/heroku/resource_heroku_domain_test.go +++ b/builtin/providers/heroku/resource_heroku_domain_test.go @@ -37,12 +37,12 @@ func TestAccHerokuDomain_Basic(t *testing.T) { func testAccCheckHerokuDomainDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*heroku.Service) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "heroku_domain" { continue } - _, err := client.DomainInfo(rs.Attributes["app"], rs.ID) + _, err := client.DomainInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err == nil { return fmt.Errorf("Domain still exists") @@ -65,25 +65,25 @@ func testAccCheckHerokuDomainAttributes(Domain *heroku.Domain) resource.TestChec func testAccCheckHerokuDomainExists(n string, Domain *heroku.Domain) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Domain ID is set") } client := testAccProvider.Meta().(*heroku.Service) - foundDomain, err := client.DomainInfo(rs.Attributes["app"], rs.ID) + foundDomain, err := client.DomainInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err != nil { return err } - if foundDomain.ID != rs.ID { + if foundDomain.ID != rs.Primary.ID { return fmt.Errorf("Domain not found") } diff --git a/builtin/providers/heroku/resource_heroku_drain.go b/builtin/providers/heroku/resource_heroku_drain.go index cd9012e2f..9c1c8f46c 100644 --- a/builtin/providers/heroku/resource_heroku_drain.go +++ b/builtin/providers/heroku/resource_heroku_drain.go @@ -6,7 +6,6 @@ import ( "github.com/cyberdelia/heroku-go/v3" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" ) func resourceHerokuDrain() *schema.Resource { @@ -52,9 +51,6 @@ func resourceHerokuDrainCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(dr.ID) d.Set("url", dr.URL) d.Set("token", dr.Token) - d.SetDependencies([]terraform.ResourceDependency{ - terraform.ResourceDependency{ID: app}, - }) log.Printf("[INFO] Drain ID: %s", d.Id()) return nil diff --git a/builtin/providers/heroku/resource_heroku_drain_test.go b/builtin/providers/heroku/resource_heroku_drain_test.go index 5ad8bbc7f..e0cf6c7a8 100644 --- a/builtin/providers/heroku/resource_heroku_drain_test.go +++ b/builtin/providers/heroku/resource_heroku_drain_test.go @@ -35,12 +35,12 @@ func TestAccHerokuDrain_Basic(t *testing.T) { func testAccCheckHerokuDrainDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*heroku.Service) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "heroku_drain" { continue } - _, err := client.LogDrainInfo(rs.Attributes["app"], rs.ID) + _, err := client.LogDrainInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err == nil { return fmt.Errorf("Drain still exists") @@ -67,25 +67,25 @@ func testAccCheckHerokuDrainAttributes(Drain *heroku.LogDrain) resource.TestChec func testAccCheckHerokuDrainExists(n string, Drain *heroku.LogDrain) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Drain ID is set") } client := testAccProvider.Meta().(*heroku.Service) - foundDrain, err := client.LogDrainInfo(rs.Attributes["app"], rs.ID) + foundDrain, err := client.LogDrainInfo(rs.Primary.Attributes["app"], rs.Primary.ID) if err != nil { return err } - if foundDrain.ID != rs.ID { + if foundDrain.ID != rs.Primary.ID { return fmt.Errorf("Drain not found") } From a590ed02df8819d3bcd430affea46b5d47c27c88 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:21:49 -0700 Subject: [PATCH 28/85] providers/mailgun: tests passing, compiling --- .../mailgun/resource_mailgun_domain_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin/providers/mailgun/resource_mailgun_domain_test.go b/builtin/providers/mailgun/resource_mailgun_domain_test.go index 2da07240f..6f6042f40 100644 --- a/builtin/providers/mailgun/resource_mailgun_domain_test.go +++ b/builtin/providers/mailgun/resource_mailgun_domain_test.go @@ -43,12 +43,12 @@ func TestAccMailgunDomain_Basic(t *testing.T) { func testAccCheckMailgunDomainDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*mailgun.Client) - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "mailgun_domain" { continue } - _, err := client.RetrieveDomain(rs.ID) + _, err := client.RetrieveDomain(rs.Primary.ID) if err == nil { return fmt.Errorf("Domain still exists") @@ -91,25 +91,25 @@ func testAccCheckMailgunDomainAttributes(DomainResp *mailgun.DomainResponse) res func testAccCheckMailgunDomainExists(n string, DomainResp *mailgun.DomainResponse) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Domain ID is set") } client := testAccProvider.Meta().(*mailgun.Client) - resp, err := client.RetrieveDomain(rs.ID) + resp, err := client.RetrieveDomain(rs.Primary.ID) if err != nil { return err } - if resp.Domain.Name != rs.ID { + if resp.Domain.Name != rs.Primary.ID { return fmt.Errorf("Domain not found") } From c2a2aca9994a5b5314ba55af2288c27137b61fd7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:24:05 -0700 Subject: [PATCH 29/85] providers/dnsimple: tests passing, compiling --- .../dnsimple/resource_dnsimple_record.go | 20 +++++++++---------- .../dnsimple/resource_dnsimple_record_test.go | 12 +++++------ .../providers/dnsimple/resource_provider.go | 17 +++++++++------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/builtin/providers/dnsimple/resource_dnsimple_record.go b/builtin/providers/dnsimple/resource_dnsimple_record.go index dd86f92d9..10455e032 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record.go @@ -11,9 +11,9 @@ import ( ) func resource_dnsimple_record_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -53,9 +53,9 @@ func resource_dnsimple_record_create( } func resource_dnsimple_record_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client rs := s.MergeDiff(d) @@ -94,7 +94,7 @@ func resource_dnsimple_record_update( } func resource_dnsimple_record_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) client := p.client @@ -111,8 +111,8 @@ func resource_dnsimple_record_destroy( } func resource_dnsimple_record_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -125,7 +125,7 @@ func resource_dnsimple_record_refresh( } func resource_dnsimple_record_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -153,8 +153,8 @@ func resource_dnsimple_record_diff( } func resource_dnsimple_record_update_state( - s *terraform.ResourceState, - rec *dnsimple.Record) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + rec *dnsimple.Record) (*terraform.InstanceState, error) { s.Attributes["name"] = rec.Name s.Attributes["value"] = rec.Content diff --git a/builtin/providers/dnsimple/resource_dnsimple_record_test.go b/builtin/providers/dnsimple/resource_dnsimple_record_test.go index 2bfba5190..78d825a0a 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record_test.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record_test.go @@ -78,12 +78,12 @@ func TestAccDNSimpleRecord_Updated(t *testing.T) { func testAccCheckDNSimpleRecordDestroy(s *terraform.State) error { client := testAccProvider.client - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "dnsimple_record" { continue } - _, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + _, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err == nil { return fmt.Errorf("Record still exists") @@ -117,25 +117,25 @@ func testAccCheckDNSimpleRecordAttributesUpdated(record *dnsimple.Record) resour func testAccCheckDNSimpleRecordExists(n string, record *dnsimple.Record) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Record ID is set") } client := testAccProvider.client - foundRecord, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + foundRecord, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err != nil { return err } - if foundRecord.StringId() != rs.ID { + if foundRecord.StringId() != rs.Primary.ID { return fmt.Errorf("Record not found") } diff --git a/builtin/providers/dnsimple/resource_provider.go b/builtin/providers/dnsimple/resource_provider.go index d2b4abba4..866271656 100644 --- a/builtin/providers/dnsimple/resource_provider.go +++ b/builtin/providers/dnsimple/resource_provider.go @@ -47,20 +47,23 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - return resourceMap.Apply(s, d, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - return resourceMap.Diff(s, c, p) + return resourceMap.Diff(info, s, c, p) } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - return resourceMap.Refresh(s, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + return resourceMap.Refresh(info, s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { From aafbc2ab7cfdddcb710af06ce45a7a37f48a9e87 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:28:22 -0700 Subject: [PATCH 30/85] providers/digitalocean: tests passing, compiling --- .../resource_digitalocean_domain_test.go | 12 ++++---- .../resource_digitalocean_droplet.go | 26 ++++++++--------- .../resource_digitalocean_droplet_test.go | 16 +++++----- .../resource_digitalocean_record.go | 6 ---- .../resource_digitalocean_record_test.go | 12 ++++---- .../digitalocean/resource_provider.go | 29 ++++++++++--------- 6 files changed, 49 insertions(+), 52 deletions(-) diff --git a/builtin/providers/digitalocean/resource_digitalocean_domain_test.go b/builtin/providers/digitalocean/resource_digitalocean_domain_test.go index 153afd2cd..ffd8be696 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_domain_test.go +++ b/builtin/providers/digitalocean/resource_digitalocean_domain_test.go @@ -35,13 +35,13 @@ func TestAccDigitalOceanDomain_Basic(t *testing.T) { func testAccCheckDigitalOceanDomainDestroy(s *terraform.State) error { client := testAccProvider.client - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "digitalocean_domain" { continue } // Try to find the domain - _, err := client.RetrieveDomain(rs.ID) + _, err := client.RetrieveDomain(rs.Primary.ID) if err == nil { fmt.Errorf("Domain still exists") @@ -64,25 +64,25 @@ func testAccCheckDigitalOceanDomainAttributes(domain *digitalocean.Domain) resou func testAccCheckDigitalOceanDomainExists(n string, domain *digitalocean.Domain) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Record ID is set") } client := testAccProvider.client - foundDomain, err := client.RetrieveDomain(rs.ID) + foundDomain, err := client.RetrieveDomain(rs.Primary.ID) if err != nil { return err } - if foundDomain.Name != rs.ID { + if foundDomain.Name != rs.Primary.ID { return fmt.Errorf("Record not found") } diff --git a/builtin/providers/digitalocean/resource_digitalocean_droplet.go b/builtin/providers/digitalocean/resource_digitalocean_droplet.go index d0fb28393..c55538582 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_droplet.go +++ b/builtin/providers/digitalocean/resource_digitalocean_droplet.go @@ -15,9 +15,9 @@ import ( ) func resource_digitalocean_droplet_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -83,16 +83,16 @@ func resource_digitalocean_droplet_create( droplet := dropletRaw.(*digitalocean.Droplet) // Initialize the connection info - rs.ConnInfo["type"] = "ssh" - rs.ConnInfo["host"] = droplet.IPV4Address("public") + rs.Ephemeral.ConnInfo["type"] = "ssh" + rs.Ephemeral.ConnInfo["host"] = droplet.IPV4Address("public") return resource_digitalocean_droplet_update_state(rs, droplet) } func resource_digitalocean_droplet_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client rs := s.MergeDiff(d) @@ -193,7 +193,7 @@ func resource_digitalocean_droplet_update( } func resource_digitalocean_droplet_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) client := p.client @@ -216,8 +216,8 @@ func resource_digitalocean_droplet_destroy( } func resource_digitalocean_droplet_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -236,7 +236,7 @@ func resource_digitalocean_droplet_refresh( } func resource_digitalocean_droplet_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -270,8 +270,8 @@ func resource_digitalocean_droplet_diff( } func resource_digitalocean_droplet_update_state( - s *terraform.ResourceState, - droplet *digitalocean.Droplet) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + droplet *digitalocean.Droplet) (*terraform.InstanceState, error) { s.Attributes["name"] = droplet.Name s.Attributes["region"] = droplet.RegionSlug() @@ -372,7 +372,7 @@ func new_droplet_state_refresh_func(id string, attribute string, client *digital // Use our mapping to get back a map of the // droplet properties resourceMap, err := resource_digitalocean_droplet_update_state( - &terraform.ResourceState{Attributes: map[string]string{}}, &droplet) + &terraform.InstanceState{Attributes: map[string]string{}}, &droplet) if err != nil { log.Printf("Error creating map from droplet: %s", err) diff --git a/builtin/providers/digitalocean/resource_digitalocean_droplet_test.go b/builtin/providers/digitalocean/resource_digitalocean_droplet_test.go index b7a9744bb..12d8a362e 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_droplet_test.go +++ b/builtin/providers/digitalocean/resource_digitalocean_droplet_test.go @@ -96,20 +96,20 @@ func TestAccDigitalOceanDroplet_PrivateNetworkingIpv6(t *testing.T) { func testAccCheckDigitalOceanDropletDestroy(s *terraform.State) error { client := testAccProvider.client - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "digitalocean_droplet" { continue } // Try to find the Droplet - _, err := client.RetrieveDroplet(rs.ID) + _, err := client.RetrieveDroplet(rs.Primary.ID) // Wait if err != nil && !strings.Contains(err.Error(), "404") { return fmt.Errorf( "Error waiting for droplet (%s) to be destroyed: %s", - rs.ID, err) + rs.Primary.ID, err) } } @@ -198,24 +198,24 @@ func testAccCheckDigitalOceanDropletAttributes_PrivateNetworkingIpv6(droplet *di func testAccCheckDigitalOceanDropletExists(n string, droplet *digitalocean.Droplet) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Droplet ID is set") } client := testAccProvider.client - retrieveDroplet, err := client.RetrieveDroplet(rs.ID) + retrieveDroplet, err := client.RetrieveDroplet(rs.Primary.ID) if err != nil { return err } - if retrieveDroplet.StringId() != rs.ID { + if retrieveDroplet.StringId() != rs.Primary.ID { return fmt.Errorf("Droplet not found") } @@ -230,7 +230,7 @@ func Test_new_droplet_state_refresh_func(t *testing.T) { Name: "foobar", } resourceMap, _ := resource_digitalocean_droplet_update_state( - &terraform.ResourceState{Attributes: map[string]string{}}, &droplet) + &terraform.InstanceState{Attributes: map[string]string{}}, &droplet) // See if we can access our attribute if _, ok := resourceMap.Attributes["name"]; !ok { diff --git a/builtin/providers/digitalocean/resource_digitalocean_record.go b/builtin/providers/digitalocean/resource_digitalocean_record.go index 06ea8922c..0ad08265e 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_record.go +++ b/builtin/providers/digitalocean/resource_digitalocean_record.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" "github.com/pearkes/digitalocean" ) @@ -152,10 +151,5 @@ func resourceRecordRead(d *schema.ResourceData, meta interface{}) error { d.Set("priority", rec.StringPriority()) d.Set("port", rec.StringPort()) - // We belong to a Domain - d.SetDependencies([]terraform.ResourceDependency{ - terraform.ResourceDependency{ID: d.Get("domain").(string)}, - }) - return nil } diff --git a/builtin/providers/digitalocean/resource_digitalocean_record_test.go b/builtin/providers/digitalocean/resource_digitalocean_record_test.go index 4b1634bbe..59a0bb4a4 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_record_test.go +++ b/builtin/providers/digitalocean/resource_digitalocean_record_test.go @@ -79,12 +79,12 @@ func TestAccDigitalOceanRecord_Updated(t *testing.T) { func testAccCheckDigitalOceanRecordDestroy(s *terraform.State) error { client := testAccProvider.client - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "digitalocean_record" { continue } - _, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + _, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err == nil { return fmt.Errorf("Record still exists") @@ -118,25 +118,25 @@ func testAccCheckDigitalOceanRecordAttributesUpdated(record *digitalocean.Record func testAccCheckDigitalOceanRecordExists(n string, record *digitalocean.Record) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Record ID is set") } client := testAccProvider.client - foundRecord, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + foundRecord, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err != nil { return err } - if foundRecord.StringId() != rs.ID { + if foundRecord.StringId() != rs.Primary.ID { return fmt.Errorf("Record not found") } diff --git a/builtin/providers/digitalocean/resource_provider.go b/builtin/providers/digitalocean/resource_provider.go index a54e13e4c..d4bcd8798 100644 --- a/builtin/providers/digitalocean/resource_provider.go +++ b/builtin/providers/digitalocean/resource_provider.go @@ -55,32 +55,35 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Apply(s, d) + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Apply(info, s, d) } - return resourceMap.Apply(s, d, p) + return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Diff(s, c) + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Diff(info, s, c) } - return resourceMap.Diff(s, c, p) + return resourceMap.Diff(info, s, c, p) } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Refresh(s) + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Refresh(info, s) } - return resourceMap.Refresh(s, p) + return resourceMap.Refresh(info, s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { From e4066595c921ee72e243145e1357b407367b3ecf Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:29:38 -0700 Subject: [PATCH 31/85] providers/consul: tests passing, compiling --- .../providers/consul/resource_consul_keys.go | 16 ++++++++-------- .../consul/resource_consul_keys_test.go | 6 +++--- builtin/providers/consul/resource_provider.go | 17 ++++++++++------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/builtin/providers/consul/resource_consul_keys.go b/builtin/providers/consul/resource_consul_keys.go index 9ab07c545..36ef6ea59 100644 --- a/builtin/providers/consul/resource_consul_keys.go +++ b/builtin/providers/consul/resource_consul_keys.go @@ -27,16 +27,16 @@ func resource_consul_keys_validation() *config.Validator { } } func resource_consul_keys_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { return resource_consul_keys_create(s, d, meta) } func resource_consul_keys_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) // Merge the diff into the state so that we have all the attributes @@ -97,7 +97,7 @@ func resource_consul_keys_create( } func resource_consul_keys_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) client := p.client @@ -132,7 +132,7 @@ func resource_consul_keys_destroy( } func resource_consul_keys_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -162,8 +162,8 @@ AFTER: } func resource_consul_keys_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client kv := client.KV() diff --git a/builtin/providers/consul/resource_consul_keys_test.go b/builtin/providers/consul/resource_consul_keys_test.go index 84429ee75..da872071d 100644 --- a/builtin/providers/consul/resource_consul_keys_test.go +++ b/builtin/providers/consul/resource_consul_keys_test.go @@ -58,13 +58,13 @@ func testAccCheckConsulKeysExists() resource.TestCheckFunc { func testAccCheckConsulKeysValue(n, attr, val string) resource.TestCheckFunc { return func(s *terraform.State) error { - rn, ok := s.Resources[n] + rn, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Resource not found") } - out, ok := rn.Attributes["var."+attr] + out, ok := rn.Primary.Attributes["var."+attr] if !ok { - return fmt.Errorf("Attribute '%s' not found: %#v", attr, rn.Attributes) + return fmt.Errorf("Attribute '%s' not found: %#v", attr, rn.Primary.Attributes) } if val != "" && out != val { return fmt.Errorf("Attribute '%s' value '%s' != '%s'", attr, out, val) diff --git a/builtin/providers/consul/resource_provider.go b/builtin/providers/consul/resource_provider.go index c2100385d..fc20caa49 100644 --- a/builtin/providers/consul/resource_provider.go +++ b/builtin/providers/consul/resource_provider.go @@ -43,20 +43,23 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - return resourceMap.Apply(s, d, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - return resourceMap.Diff(s, c, p) + return resourceMap.Diff(info, s, c, p) } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - return resourceMap.Refresh(s, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + return resourceMap.Refresh(info, s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { From 78471d2aa06aa5257843f6848736fb4e14bfe1cb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:31:07 -0700 Subject: [PATCH 32/85] providers/cloudflare: tests passing, compiles --- .../cloudflare/resource_cloudflare_record.go | 20 +++++++++---------- .../resource_cloudflare_record_test.go | 12 +++++------ .../providers/cloudflare/resource_provider.go | 17 +++++++++------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/builtin/providers/cloudflare/resource_cloudflare_record.go b/builtin/providers/cloudflare/resource_cloudflare_record.go index 25be2532f..f03905490 100644 --- a/builtin/providers/cloudflare/resource_cloudflare_record.go +++ b/builtin/providers/cloudflare/resource_cloudflare_record.go @@ -11,9 +11,9 @@ import ( ) func resource_cloudflare_record_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -51,9 +51,9 @@ func resource_cloudflare_record_create( } func resource_cloudflare_record_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client rs := s.MergeDiff(d) @@ -86,7 +86,7 @@ func resource_cloudflare_record_update( } func resource_cloudflare_record_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) client := p.client @@ -103,8 +103,8 @@ func resource_cloudflare_record_destroy( } func resource_cloudflare_record_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -117,7 +117,7 @@ func resource_cloudflare_record_refresh( } func resource_cloudflare_record_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -144,8 +144,8 @@ func resource_cloudflare_record_diff( } func resource_cloudflare_record_update_state( - s *terraform.ResourceState, - rec *cloudflare.Record) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + rec *cloudflare.Record) (*terraform.InstanceState, error) { s.Attributes["name"] = rec.Name s.Attributes["value"] = rec.Value diff --git a/builtin/providers/cloudflare/resource_cloudflare_record_test.go b/builtin/providers/cloudflare/resource_cloudflare_record_test.go index 40a537c3e..9ebfaa5a5 100644 --- a/builtin/providers/cloudflare/resource_cloudflare_record_test.go +++ b/builtin/providers/cloudflare/resource_cloudflare_record_test.go @@ -78,12 +78,12 @@ func TestAccCLOudflareRecord_Updated(t *testing.T) { func testAccCheckCLOudflareRecordDestroy(s *terraform.State) error { client := testAccProvider.client - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "cloudflare_record" { continue } - _, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + _, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err == nil { return fmt.Errorf("Record still exists") @@ -117,25 +117,25 @@ func testAccCheckCLOudflareRecordAttributesUpdated(record *cloudflare.Record) re func testAccCheckCLOudflareRecordExists(n string, record *cloudflare.Record) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Record ID is set") } client := testAccProvider.client - foundRecord, err := client.RetrieveRecord(rs.Attributes["domain"], rs.ID) + foundRecord, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) if err != nil { return err } - if foundRecord.Id != rs.ID { + if foundRecord.Id != rs.Primary.ID { return fmt.Errorf("Record not found") } diff --git a/builtin/providers/cloudflare/resource_provider.go b/builtin/providers/cloudflare/resource_provider.go index 808518254..ce1dcdc31 100644 --- a/builtin/providers/cloudflare/resource_provider.go +++ b/builtin/providers/cloudflare/resource_provider.go @@ -47,20 +47,23 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - return resourceMap.Apply(s, d, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - return resourceMap.Diff(s, c, p) + return resourceMap.Diff(info, s, c, p) } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - return resourceMap.Refresh(s, p) + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + return resourceMap.Refresh(info, s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { From edccc2de3f0fa5eb340a264d02710c833efa6374 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 17:23:01 -0700 Subject: [PATCH 33/85] terraform: fixing provisioner invocation --- terraform/context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/context.go b/terraform/context.go index 3fd26ce56..73f9b94ed 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -629,7 +629,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // Additionally, we need to be careful to not run this if there // was an error during the provider apply. tainted := false - if applyerr == nil && r.State.Primary.ID == "" && len(r.Provisioners) > 0 { + if applyerr == nil && r.State.Primary.ID != "" && len(r.Provisioners) > 0 { for _, h := range c.hooks { handleHook(h.PreProvisionResource(r.Id, r.State)) } From 71782c57b3898e31cb01ee58da97170e1a63b5cb Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Tue, 16 Sep 2014 17:27:14 -0700 Subject: [PATCH 34/85] terraform: emit ID of tainted resource in string --- terraform/state.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/terraform/state.go b/terraform/state.go index 0ea366610..fd5a7926f 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -122,7 +122,11 @@ func (s *State) String() string { id = rs.Primary.ID } if id == "" { - id = "" + if len(rs.Tainted) > 0 { + id = rs.Tainted[0].ID + } else { + id = "" + } } taintStr := "" From c5d6df692d651a65bf455f599f5a02cd5cede742 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 17:44:42 -0700 Subject: [PATCH 35/85] providers/aws: tests passing, compiles --- .../aws/resource_aws_autoscaling_group.go | 23 ++++++-------- .../resource_aws_autoscaling_group_test.go | 14 ++++----- .../providers/aws/resource_aws_db_instance.go | 27 ++++++---------- .../aws/resource_aws_db_instance_test.go | 14 ++++----- .../aws/resource_aws_db_security_group.go | 20 ++++++------ .../resource_aws_db_security_group_test.go | 14 ++++----- .../providers/aws/resource_aws_eip_test.go | 20 ++++++------ builtin/providers/aws/resource_aws_elb.go | 20 ++++++------ .../providers/aws/resource_aws_elb_test.go | 14 ++++----- .../providers/aws/resource_aws_instance.go | 11 ------- .../aws/resource_aws_instance_test.go | 10 +++--- .../aws/resource_aws_internet_gateway.go | 31 +++++++------------ .../aws/resource_aws_internet_gateway_test.go | 10 +++--- .../aws/resource_aws_launch_configuration.go | 20 ++++++------ .../resource_aws_launch_configuration_test.go | 14 ++++----- .../aws/resource_aws_route53_record.go | 19 +++++------- .../aws/resource_aws_route53_record_test.go | 10 +++--- .../aws/resource_aws_route53_zone.go | 12 +++---- .../aws/resource_aws_route53_zone_test.go | 10 +++--- .../providers/aws/resource_aws_route_table.go | 25 ++++++--------- .../resource_aws_route_table_association.go | 24 +++++--------- ...source_aws_route_table_association_test.go | 10 +++--- .../aws/resource_aws_route_table_test.go | 10 +++--- .../providers/aws/resource_aws_s3_bucket.go | 12 +++---- .../aws/resource_aws_s3_bucket_test.go | 10 +++--- .../aws/resource_aws_security_group.go | 17 ---------- .../aws/resource_aws_security_group_test.go | 16 +++++----- builtin/providers/aws/resource_aws_subnet.go | 25 ++++++--------- .../providers/aws/resource_aws_subnet_test.go | 10 +++--- builtin/providers/aws/resource_aws_vpc.go | 20 ++++++------ .../providers/aws/resource_aws_vpc_test.go | 10 +++--- builtin/providers/aws/resource_provider.go | 29 +++++++++-------- 32 files changed, 234 insertions(+), 297 deletions(-) diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index dfef1250f..4bd807f41 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -13,9 +13,9 @@ import ( ) func resource_aws_autoscaling_group_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -81,9 +81,6 @@ func resource_aws_autoscaling_group_create( } rs.ID = rs.Attributes["name"] - rs.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: rs.Attributes["launch_configuration"]}, - } log.Printf("[INFO] AutoScaling Group ID: %s", rs.ID) @@ -96,9 +93,9 @@ func resource_aws_autoscaling_group_create( } func resource_aws_autoscaling_group_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn rs := s.MergeDiff(d) @@ -141,7 +138,7 @@ func resource_aws_autoscaling_group_update( } func resource_aws_autoscaling_group_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -173,8 +170,8 @@ func resource_aws_autoscaling_group_destroy( } func resource_aws_autoscaling_group_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -188,7 +185,7 @@ func resource_aws_autoscaling_group_refresh( } func resource_aws_autoscaling_group_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -223,8 +220,8 @@ func resource_aws_autoscaling_group_diff( } func resource_aws_autoscaling_group_update_state( - s *terraform.ResourceState, - g *autoscaling.AutoScalingGroup) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + g *autoscaling.AutoScalingGroup) (*terraform.InstanceState, error) { s.Attributes["min_size"] = strconv.Itoa(g.MinSize) s.Attributes["max_size"] = strconv.Itoa(g.MaxSize) diff --git a/builtin/providers/aws/resource_aws_autoscaling_group_test.go b/builtin/providers/aws/resource_aws_autoscaling_group_test.go index 453e5c74c..fd23ad470 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group_test.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group_test.go @@ -65,7 +65,7 @@ func TestAccAWSAutoScalingGroupWithLoadBalancer(t *testing.T) { func testAccCheckAWSAutoScalingGroupDestroy(s *terraform.State) error { conn := testAccProvider.autoscalingconn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_autoscaling_group" { continue } @@ -73,12 +73,12 @@ func testAccCheckAWSAutoScalingGroupDestroy(s *terraform.State) error { // Try to find the Group describeGroups, err := conn.DescribeAutoScalingGroups( &autoscaling.DescribeAutoScalingGroups{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, }) if err == nil { if len(describeGroups.AutoScalingGroups) != 0 && - describeGroups.AutoScalingGroups[0].Name == rs.ID { + describeGroups.AutoScalingGroups[0].Name == rs.Primary.ID { return fmt.Errorf("AutoScaling Group still exists") } } @@ -146,19 +146,19 @@ func testAccCheckAWSAutoScalingGroupAttributesLoadBalancer(group *autoscaling.Au func testAccCheckAWSAutoScalingGroupExists(n string, group *autoscaling.AutoScalingGroup) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No AutoScaling Group ID is set") } conn := testAccProvider.autoscalingconn describeOpts := autoscaling.DescribeAutoScalingGroups{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, } describeGroups, err := conn.DescribeAutoScalingGroups(&describeOpts) @@ -167,7 +167,7 @@ func testAccCheckAWSAutoScalingGroupExists(n string, group *autoscaling.AutoScal } if len(describeGroups.AutoScalingGroups) != 1 || - describeGroups.AutoScalingGroups[0].Name != rs.ID { + describeGroups.AutoScalingGroups[0].Name != rs.Primary.ID { return fmt.Errorf("AutoScaling Group not found") } diff --git a/builtin/providers/aws/resource_aws_db_instance.go b/builtin/providers/aws/resource_aws_db_instance.go index a10dace3b..79a716992 100644 --- a/builtin/providers/aws/resource_aws_db_instance.go +++ b/builtin/providers/aws/resource_aws_db_instance.go @@ -16,9 +16,9 @@ import ( ) func resource_aws_db_instance_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -136,14 +136,14 @@ func resource_aws_db_instance_create( } func resource_aws_db_instance_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { panic("Cannot update DB") } func resource_aws_db_instance_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -184,8 +184,8 @@ func resource_aws_db_instance_destroy( } func resource_aws_db_instance_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -199,7 +199,7 @@ func resource_aws_db_instance_refresh( } func resource_aws_db_instance_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -247,8 +247,8 @@ func resource_aws_db_instance_diff( } func resource_aws_db_instance_update_state( - s *terraform.ResourceState, - v *rds.DBInstance) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + v *rds.DBInstance) (*terraform.InstanceState, error) { s.Attributes["address"] = v.Address s.Attributes["allocated_storage"] = strconv.Itoa(v.AllocatedStorage) @@ -279,13 +279,6 @@ func resource_aws_db_instance_update_state( s.Attributes[k] = v } - // We depend on any security groups attached - for _, g := range v.DBSecurityGroupNames { - s.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: g}, - } - } - return s, nil } diff --git a/builtin/providers/aws/resource_aws_db_instance_test.go b/builtin/providers/aws/resource_aws_db_instance_test.go index a4ef480f0..05073fe93 100644 --- a/builtin/providers/aws/resource_aws_db_instance_test.go +++ b/builtin/providers/aws/resource_aws_db_instance_test.go @@ -52,7 +52,7 @@ func TestAccAWSDBInstance(t *testing.T) { func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { conn := testAccProvider.rdsconn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_db_instance" { continue } @@ -60,12 +60,12 @@ func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { // Try to find the Group resp, err := conn.DescribeDBInstances( &rds.DescribeDBInstances{ - DBInstanceIdentifier: rs.ID, + DBInstanceIdentifier: rs.Primary.ID, }) if err == nil { if len(resp.DBInstances) != 0 && - resp.DBInstances[0].DBInstanceIdentifier == rs.ID { + resp.DBInstances[0].DBInstanceIdentifier == rs.Primary.ID { return fmt.Errorf("DB Instance still exists") } } @@ -104,19 +104,19 @@ func testAccCheckAWSDBInstanceAttributes(v *rds.DBInstance) resource.TestCheckFu func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No DB Instance ID is set") } conn := testAccProvider.rdsconn opts := rds.DescribeDBInstances{ - DBInstanceIdentifier: rs.ID, + DBInstanceIdentifier: rs.Primary.ID, } resp, err := conn.DescribeDBInstances(&opts) @@ -126,7 +126,7 @@ func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestC } if len(resp.DBInstances) != 1 || - resp.DBInstances[0].DBInstanceIdentifier != rs.ID { + resp.DBInstances[0].DBInstanceIdentifier != rs.Primary.ID { return fmt.Errorf("DB Instance not found") } diff --git a/builtin/providers/aws/resource_aws_db_security_group.go b/builtin/providers/aws/resource_aws_db_security_group.go index fab93cd72..d9eacd9ac 100644 --- a/builtin/providers/aws/resource_aws_db_security_group.go +++ b/builtin/providers/aws/resource_aws_db_security_group.go @@ -15,9 +15,9 @@ import ( ) func resource_aws_db_security_group_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -85,14 +85,14 @@ func resource_aws_db_security_group_create( } func resource_aws_db_security_group_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { panic("Cannot update DB security group") } func resource_aws_db_security_group_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -116,8 +116,8 @@ func resource_aws_db_security_group_destroy( } func resource_aws_db_security_group_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -131,7 +131,7 @@ func resource_aws_db_security_group_refresh( } func resource_aws_db_security_group_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -152,8 +152,8 @@ func resource_aws_db_security_group_diff( } func resource_aws_db_security_group_update_state( - s *terraform.ResourceState, - v *rds.DBSecurityGroup) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + v *rds.DBSecurityGroup) (*terraform.InstanceState, error) { s.Attributes["name"] = v.Name s.Attributes["description"] = v.Description diff --git a/builtin/providers/aws/resource_aws_db_security_group_test.go b/builtin/providers/aws/resource_aws_db_security_group_test.go index e26e0f479..f81ac2537 100644 --- a/builtin/providers/aws/resource_aws_db_security_group_test.go +++ b/builtin/providers/aws/resource_aws_db_security_group_test.go @@ -39,7 +39,7 @@ func TestAccAWSDBSecurityGroup(t *testing.T) { func testAccCheckAWSDBSecurityGroupDestroy(s *terraform.State) error { conn := testAccProvider.rdsconn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_db_security_group" { continue } @@ -47,12 +47,12 @@ func testAccCheckAWSDBSecurityGroupDestroy(s *terraform.State) error { // Try to find the Group resp, err := conn.DescribeDBSecurityGroups( &rds.DescribeDBSecurityGroups{ - DBSecurityGroupName: rs.ID, + DBSecurityGroupName: rs.Primary.ID, }) if err == nil { if len(resp.DBSecurityGroups) != 0 && - resp.DBSecurityGroups[0].Name == rs.ID { + resp.DBSecurityGroups[0].Name == rs.Primary.ID { return fmt.Errorf("DB Security Group still exists") } } @@ -98,19 +98,19 @@ func testAccCheckAWSDBSecurityGroupAttributes(group *rds.DBSecurityGroup) resour func testAccCheckAWSDBSecurityGroupExists(n string, v *rds.DBSecurityGroup) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No DB Security Group ID is set") } conn := testAccProvider.rdsconn opts := rds.DescribeDBSecurityGroups{ - DBSecurityGroupName: rs.ID, + DBSecurityGroupName: rs.Primary.ID, } resp, err := conn.DescribeDBSecurityGroups(&opts) @@ -120,7 +120,7 @@ func testAccCheckAWSDBSecurityGroupExists(n string, v *rds.DBSecurityGroup) reso } if len(resp.DBSecurityGroups) != 1 || - resp.DBSecurityGroups[0].Name != rs.ID { + resp.DBSecurityGroups[0].Name != rs.Primary.ID { return fmt.Errorf("DB Security Group not found") } diff --git a/builtin/providers/aws/resource_aws_eip_test.go b/builtin/providers/aws/resource_aws_eip_test.go index 63f2a42f1..b0272bd52 100644 --- a/builtin/providers/aws/resource_aws_eip_test.go +++ b/builtin/providers/aws/resource_aws_eip_test.go @@ -59,16 +59,16 @@ func TestAccAWSEIP_instance(t *testing.T) { func testAccCheckAWSEIPDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_eip" { continue } - describe, err := conn.Addresses([]string{rs.ID}, []string{}, nil) + describe, err := conn.Addresses([]string{rs.Primary.ID}, []string{}, nil) if err == nil { if len(describe.Addresses) != 0 && - describe.Addresses[0].PublicIp == rs.ID { + describe.Addresses[0].PublicIp == rs.Primary.ID { return fmt.Errorf("EIP still exists") } } @@ -103,37 +103,37 @@ func testAccCheckAWSEIPAttributes(conf *ec2.Address) resource.TestCheckFunc { func testAccCheckAWSEIPExists(n string, res *ec2.Address) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No EIP ID is set") } conn := testAccProvider.ec2conn - if strings.Contains(rs.ID, "eipalloc") { - describe, err := conn.Addresses([]string{}, []string{rs.ID}, nil) + if strings.Contains(rs.Primary.ID, "eipalloc") { + describe, err := conn.Addresses([]string{}, []string{rs.Primary.ID}, nil) if err != nil { return err } if len(describe.Addresses) != 1 || - describe.Addresses[0].AllocationId != rs.ID { + describe.Addresses[0].AllocationId != rs.Primary.ID { return fmt.Errorf("EIP not found") } *res = describe.Addresses[0] } else { - describe, err := conn.Addresses([]string{rs.ID}, []string{}, nil) + describe, err := conn.Addresses([]string{rs.Primary.ID}, []string{}, nil) if err != nil { return err } if len(describe.Addresses) != 1 || - describe.Addresses[0].PublicIp != rs.ID { + describe.Addresses[0].PublicIp != rs.Primary.ID { return fmt.Errorf("EIP not found") } *res = describe.Addresses[0] diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 22746acb9..5fd512a77 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -13,9 +13,9 @@ import ( ) func resource_aws_elb_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -124,9 +124,9 @@ func resource_aws_elb_create( } func resource_aws_elb_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -214,7 +214,7 @@ func resource_aws_elb_update( } func resource_aws_elb_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -235,8 +235,8 @@ func resource_aws_elb_destroy( } func resource_aws_elb_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -249,7 +249,7 @@ func resource_aws_elb_refresh( } func resource_aws_elb_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -273,8 +273,8 @@ func resource_aws_elb_diff( } func resource_aws_elb_update_state( - s *terraform.ResourceState, - balancer *elb.LoadBalancer) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + balancer *elb.LoadBalancer) (*terraform.InstanceState, error) { s.Attributes["name"] = balancer.LoadBalancerName s.Attributes["dns_name"] = balancer.DNSName diff --git a/builtin/providers/aws/resource_aws_elb_test.go b/builtin/providers/aws/resource_aws_elb_test.go index 7edeb6d85..a0a1c657c 100644 --- a/builtin/providers/aws/resource_aws_elb_test.go +++ b/builtin/providers/aws/resource_aws_elb_test.go @@ -112,18 +112,18 @@ func TestAccAWSELB_HealthCheck(t *testing.T) { func testAccCheckAWSELBDestroy(s *terraform.State) error { conn := testAccProvider.elbconn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_elb" { continue } describe, err := conn.DescribeLoadBalancers(&elb.DescribeLoadBalancer{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, }) if err == nil { if len(describe.LoadBalancers) != 0 && - describe.LoadBalancers[0].LoadBalancerName == rs.ID { + describe.LoadBalancers[0].LoadBalancerName == rs.Primary.ID { return fmt.Errorf("ELB still exists") } } @@ -209,19 +209,19 @@ func testAccCheckAWSELBAttributesHealthCheck(conf *elb.LoadBalancer) resource.Te func testAccCheckAWSELBExists(n string, res *elb.LoadBalancer) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ELB ID is set") } conn := testAccProvider.elbconn describe, err := conn.DescribeLoadBalancers(&elb.DescribeLoadBalancer{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, }) if err != nil { @@ -229,7 +229,7 @@ func testAccCheckAWSELBExists(n string, res *elb.LoadBalancer) resource.TestChec } if len(describe.LoadBalancers) != 1 || - describe.LoadBalancers[0].LoadBalancerName != rs.ID { + describe.LoadBalancers[0].LoadBalancerName != rs.Primary.ID { return fmt.Errorf("ELB not found") } diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index ffe2256ea..b97981c16 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/ec2" ) @@ -315,8 +314,6 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { d.Set("subnet_id", instance.SubnetId) d.Set("ebs_optimized", instance.EbsOptimized) - var deps []terraform.ResourceDependency - // Determine whether we're referring to security groups with // IDs or names. We use a heuristic to figure this out. By default, // we use IDs if we're in a VPC. However, if we previously had an @@ -343,17 +340,9 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { } else { sgs[i] = sg.Name } - - deps = append(deps, terraform.ResourceDependency{ID: sg.Id}) } d.Set("security_groups", sgs) - // If we're in a VPC, we depend on the subnet - if instance.SubnetId != "" { - deps = append(deps, terraform.ResourceDependency{ID: instance.SubnetId}) - } - - d.SetDependencies(deps) return nil } diff --git a/builtin/providers/aws/resource_aws_instance_test.go b/builtin/providers/aws/resource_aws_instance_test.go index 8d6f88fb3..ec679fe1b 100644 --- a/builtin/providers/aws/resource_aws_instance_test.go +++ b/builtin/providers/aws/resource_aws_instance_test.go @@ -125,14 +125,14 @@ func TestAccAWSInstance_vpc(t *testing.T) { func testAccCheckInstanceDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_instance" { continue } // Try to find the resource resp, err := conn.Instances( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err == nil { if len(resp.Reservations) > 0 { return fmt.Errorf("still exist.") @@ -156,18 +156,18 @@ func testAccCheckInstanceDestroy(s *terraform.State) error { func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } conn := testAccProvider.ec2conn resp, err := conn.Instances( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_aws_internet_gateway.go b/builtin/providers/aws/resource_aws_internet_gateway.go index b0a0b9aab..9a60d0333 100644 --- a/builtin/providers/aws/resource_aws_internet_gateway.go +++ b/builtin/providers/aws/resource_aws_internet_gateway.go @@ -12,9 +12,9 @@ import ( ) func resource_aws_internet_gateway_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -35,9 +35,9 @@ func resource_aws_internet_gateway_create( } func resource_aws_internet_gateway_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -70,7 +70,7 @@ func resource_aws_internet_gateway_update( } func resource_aws_internet_gateway_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -108,8 +108,8 @@ func resource_aws_internet_gateway_destroy( } func resource_aws_internet_gateway_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -126,7 +126,7 @@ func resource_aws_internet_gateway_refresh( } func resource_aws_internet_gateway_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ @@ -140,7 +140,7 @@ func resource_aws_internet_gateway_diff( func resource_aws_internet_gateway_attach( ec2conn *ec2.EC2, - s *terraform.ResourceState, + s *terraform.InstanceState, vpcId string) error { log.Printf( "[INFO] Attaching Internet Gateway '%s' to VPC '%s'", @@ -170,7 +170,7 @@ func resource_aws_internet_gateway_attach( func resource_aws_internet_gateway_detach( ec2conn *ec2.EC2, - s *terraform.ResourceState) error { + s *terraform.InstanceState) error { if s.Attributes["vpc_id"] == "" { return nil } @@ -222,15 +222,8 @@ func resource_aws_internet_gateway_detach( } func resource_aws_internet_gateway_update_state( - s *terraform.ResourceState, - ig *ec2.InternetGateway) (*terraform.ResourceState, error) { - if s.Attributes["vpc_id"] != "" { - // We belong to a VPC - s.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: s.Attributes["vpc_id"]}, - } - } - + s *terraform.InstanceState, + ig *ec2.InternetGateway) (*terraform.InstanceState, error) { return s, nil } diff --git a/builtin/providers/aws/resource_aws_internet_gateway_test.go b/builtin/providers/aws/resource_aws_internet_gateway_test.go index d38324d70..a5974cf25 100644 --- a/builtin/providers/aws/resource_aws_internet_gateway_test.go +++ b/builtin/providers/aws/resource_aws_internet_gateway_test.go @@ -57,14 +57,14 @@ func TestAccAWSInternetGateway(t *testing.T) { func testAccCheckInternetGatewayDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_internet_gateway" { continue } // Try to find the resource resp, err := conn.DescribeInternetGateways( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err == nil { if len(resp.InternetGateways) > 0 { return fmt.Errorf("still exist.") @@ -88,18 +88,18 @@ func testAccCheckInternetGatewayDestroy(s *terraform.State) error { func testAccCheckInternetGatewayExists(n string, ig *ec2.InternetGateway) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } conn := testAccProvider.ec2conn resp, err := conn.DescribeInternetGateways( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_aws_launch_configuration.go b/builtin/providers/aws/resource_aws_launch_configuration.go index 87d97a2ce..6e39aa53c 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration.go +++ b/builtin/providers/aws/resource_aws_launch_configuration.go @@ -12,9 +12,9 @@ import ( ) func resource_aws_launch_configuration_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -75,14 +75,14 @@ func resource_aws_launch_configuration_create( } func resource_aws_launch_configuration_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { panic("Update for AWS Launch Configuration is not supported") } func resource_aws_launch_configuration_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -103,8 +103,8 @@ func resource_aws_launch_configuration_destroy( } func resource_aws_launch_configuration_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -118,7 +118,7 @@ func resource_aws_launch_configuration_refresh( } func resource_aws_launch_configuration_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { @@ -142,8 +142,8 @@ func resource_aws_launch_configuration_diff( } func resource_aws_launch_configuration_update_state( - s *terraform.ResourceState, - lc *autoscaling.LaunchConfiguration) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + lc *autoscaling.LaunchConfiguration) (*terraform.InstanceState, error) { s.Attributes["image_id"] = lc.ImageId s.Attributes["instance_type"] = lc.InstanceType diff --git a/builtin/providers/aws/resource_aws_launch_configuration_test.go b/builtin/providers/aws/resource_aws_launch_configuration_test.go index 5b75f5d17..153d276db 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration_test.go +++ b/builtin/providers/aws/resource_aws_launch_configuration_test.go @@ -40,19 +40,19 @@ func TestAccAWSLaunchConfiguration(t *testing.T) { func testAccCheckAWSLaunchConfigurationDestroy(s *terraform.State) error { conn := testAccProvider.autoscalingconn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_launch_configuration" { continue } describe, err := conn.DescribeLaunchConfigurations( &autoscaling.DescribeLaunchConfigurations{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, }) if err == nil { if len(describe.LaunchConfigurations) != 0 && - describe.LaunchConfigurations[0].Name == rs.ID { + describe.LaunchConfigurations[0].Name == rs.Primary.ID { return fmt.Errorf("Launch Configuration still exists") } } @@ -94,19 +94,19 @@ func testAccCheckAWSLaunchConfigurationAttributes(conf *autoscaling.LaunchConfig func testAccCheckAWSLaunchConfigurationExists(n string, res *autoscaling.LaunchConfiguration) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Launch Configuration ID is set") } conn := testAccProvider.autoscalingconn describeOpts := autoscaling.DescribeLaunchConfigurations{ - Names: []string{rs.ID}, + Names: []string{rs.Primary.ID}, } describe, err := conn.DescribeLaunchConfigurations(&describeOpts) @@ -115,7 +115,7 @@ func testAccCheckAWSLaunchConfigurationExists(n string, res *autoscaling.LaunchC } if len(describe.LaunchConfigurations) != 1 || - describe.LaunchConfigurations[0].Name != rs.ID { + describe.LaunchConfigurations[0].Name != rs.Primary.ID { return fmt.Errorf("Launch Configuration Group not found") } diff --git a/builtin/providers/aws/resource_aws_route53_record.go b/builtin/providers/aws/resource_aws_route53_record.go index e385090b0..da530ba34 100644 --- a/builtin/providers/aws/resource_aws_route53_record.go +++ b/builtin/providers/aws/resource_aws_route53_record.go @@ -28,9 +28,9 @@ func resource_aws_r53_record_validation() *config.Validator { } func resource_aws_r53_record_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.route53 @@ -87,9 +87,6 @@ func resource_aws_r53_record_create( // Generate an ID rs.ID = fmt.Sprintf("%s_%s_%s", zone, rs.Attributes["name"], rs.Attributes["type"]) - rs.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: zone}, - } // Wait until we are done wait = resource.StateChangeConf{ @@ -109,7 +106,7 @@ func resource_aws_r53_record_create( return rs, nil } -func resource_aws_r53_build_record_set(s *terraform.ResourceState) (*route53.ResourceRecordSet, error) { +func resource_aws_r53_build_record_set(s *terraform.InstanceState) (*route53.ResourceRecordSet, error) { // Parse the TTL ttl, err := strconv.ParseInt(s.Attributes["ttl"], 10, 32) if err != nil { @@ -133,7 +130,7 @@ func resource_aws_r53_build_record_set(s *terraform.ResourceState) (*route53.Res } func resource_aws_r53_record_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) conn := p.route53 @@ -185,8 +182,8 @@ func resource_aws_r53_record_destroy( } func resource_aws_r53_record_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.route53 @@ -221,7 +218,7 @@ func resource_aws_r53_record_refresh( } func resource_aws_r53_record_update_state( - s *terraform.ResourceState, + s *terraform.InstanceState, rec *route53.ResourceRecordSet) { flatRec := flatmap.Flatten(map[string]interface{}{ @@ -235,7 +232,7 @@ func resource_aws_r53_record_update_state( } func resource_aws_r53_record_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ diff --git a/builtin/providers/aws/resource_aws_route53_record_test.go b/builtin/providers/aws/resource_aws_route53_record_test.go index 562f54fda..c22fc994f 100644 --- a/builtin/providers/aws/resource_aws_route53_record_test.go +++ b/builtin/providers/aws/resource_aws_route53_record_test.go @@ -28,12 +28,12 @@ func TestAccRoute53Record(t *testing.T) { func testAccCheckRoute53RecordDestroy(s *terraform.State) error { conn := testAccProvider.route53 - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route53_record" { continue } - parts := strings.Split(rs.ID, "_") + parts := strings.Split(rs.Primary.ID, "_") zone := parts[0] name := parts[1] rType := parts[2] @@ -57,16 +57,16 @@ func testAccCheckRoute53RecordDestroy(s *terraform.State) error { func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.route53 - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No hosted zone ID is set") } - parts := strings.Split(rs.ID, "_") + parts := strings.Split(rs.Primary.ID, "_") zone := parts[0] name := parts[1] rType := parts[2] diff --git a/builtin/providers/aws/resource_aws_route53_zone.go b/builtin/providers/aws/resource_aws_route53_zone.go index 599ba2eab..ef93da00f 100644 --- a/builtin/providers/aws/resource_aws_route53_zone.go +++ b/builtin/providers/aws/resource_aws_route53_zone.go @@ -21,9 +21,9 @@ func resource_aws_r53_zone_validation() *config.Validator { } func resource_aws_r53_zone_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) r53 := p.route53 @@ -74,7 +74,7 @@ func resource_aws_r53_wait(r53 *route53.Route53, ref string) (result interface{} } func resource_aws_r53_zone_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) r53 := p.route53 @@ -89,8 +89,8 @@ func resource_aws_r53_zone_destroy( } func resource_aws_r53_zone_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) r53 := p.route53 @@ -107,7 +107,7 @@ func resource_aws_r53_zone_refresh( } func resource_aws_r53_zone_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { diff --git a/builtin/providers/aws/resource_aws_route53_zone_test.go b/builtin/providers/aws/resource_aws_route53_zone_test.go index 0969abeb3..45475a1a3 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_test.go +++ b/builtin/providers/aws/resource_aws_route53_zone_test.go @@ -26,12 +26,12 @@ func TestAccRoute53Zone(t *testing.T) { func testAccCheckRoute53ZoneDestroy(s *terraform.State) error { conn := testAccProvider.route53 - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route53_zone" { continue } - _, err := conn.GetHostedZone(rs.ID) + _, err := conn.GetHostedZone(rs.Primary.ID) if err == nil { return fmt.Errorf("Hosted zone still exists") } @@ -41,17 +41,17 @@ func testAccCheckRoute53ZoneDestroy(s *terraform.State) error { func testAccCheckRoute53ZoneExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No hosted zone ID is set") } conn := testAccProvider.route53 - _, err := conn.GetHostedZone(rs.ID) + _, err := conn.GetHostedZone(rs.Primary.ID) if err != nil { return fmt.Errorf("Hosted zone err: %v", err) } diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index 7ba631903..46249a347 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -14,9 +14,9 @@ import ( ) func resource_aws_route_table_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -56,9 +56,9 @@ func resource_aws_route_table_create( } func resource_aws_route_table_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -133,7 +133,7 @@ func resource_aws_route_table_update( } func resource_aws_route_table_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -188,8 +188,8 @@ func resource_aws_route_table_destroy( } func resource_aws_route_table_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -206,7 +206,7 @@ func resource_aws_route_table_refresh( } func resource_aws_route_table_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ @@ -220,15 +220,10 @@ func resource_aws_route_table_diff( } func resource_aws_route_table_update_state( - s *terraform.ResourceState, - rt *ec2.RouteTable) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + rt *ec2.RouteTable) (*terraform.InstanceState, error) { s.Attributes["vpc_id"] = rt.VpcId - // We belong to a VPC - s.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: rt.VpcId}, - } - return s, nil } diff --git a/builtin/providers/aws/resource_aws_route_table_association.go b/builtin/providers/aws/resource_aws_route_table_association.go index 828508262..3d1b53c6d 100644 --- a/builtin/providers/aws/resource_aws_route_table_association.go +++ b/builtin/providers/aws/resource_aws_route_table_association.go @@ -10,9 +10,9 @@ import ( ) func resource_aws_route_table_association_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn rs := s.MergeDiff(d) @@ -32,17 +32,13 @@ func resource_aws_route_table_association_create( rs.ID = resp.AssociationId log.Printf("[INFO] Association ID: %s", rs.ID) - rs.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: rs.Attributes["route_table_id"]}, - } - return rs, nil } func resource_aws_route_table_association_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -68,15 +64,11 @@ func resource_aws_route_table_association_update( rs.ID = resp.AssociationId log.Printf("[INFO] Association ID: %s", rs.ID) - rs.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: rs.Attributes["route_table_id"]}, - } - return rs, nil } func resource_aws_route_table_association_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -95,8 +87,8 @@ func resource_aws_route_table_association_destroy( } func resource_aws_route_table_association_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -128,7 +120,7 @@ func resource_aws_route_table_association_refresh( } func resource_aws_route_table_association_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ diff --git a/builtin/providers/aws/resource_aws_route_table_association_test.go b/builtin/providers/aws/resource_aws_route_table_association_test.go index 54dc75637..bc670cdf5 100644 --- a/builtin/providers/aws/resource_aws_route_table_association_test.go +++ b/builtin/providers/aws/resource_aws_route_table_association_test.go @@ -39,14 +39,14 @@ func TestAccAWSRouteTableAssociation(t *testing.T) { func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route_table_association" { continue } // Try to find the resource resp, err := conn.DescribeRouteTables( - []string{rs.Attributes["route_table_Id"]}, ec2.NewFilter()) + []string{rs.Primary.Attributes["route_table_Id"]}, ec2.NewFilter()) if err != nil { // Verify the error is what we want ec2err, ok := err.(*ec2.Error) @@ -72,18 +72,18 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTable) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } conn := testAccProvider.ec2conn resp, err := conn.DescribeRouteTables( - []string{rs.Attributes["route_table_id"]}, ec2.NewFilter()) + []string{rs.Primary.Attributes["route_table_id"]}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_aws_route_table_test.go b/builtin/providers/aws/resource_aws_route_table_test.go index 6175313da..2fbe2433f 100644 --- a/builtin/providers/aws/resource_aws_route_table_test.go +++ b/builtin/providers/aws/resource_aws_route_table_test.go @@ -124,14 +124,14 @@ func TestAccAWSRouteTable_instance(t *testing.T) { func testAccCheckRouteTableDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route_table" { continue } // Try to find the resource resp, err := conn.DescribeRouteTables( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err == nil { if len(resp.RouteTables) > 0 { return fmt.Errorf("still exist.") @@ -155,18 +155,18 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error { func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } conn := testAccProvider.ec2conn resp, err := conn.DescribeRouteTables( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index 3dc3f7a2f..2d9d184a8 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -22,9 +22,9 @@ func resource_aws_s3_bucket_validation() *config.Validator { } func resource_aws_s3_bucket_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) s3conn := p.s3conn @@ -52,7 +52,7 @@ func resource_aws_s3_bucket_create( } func resource_aws_s3_bucket_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) s3conn := p.s3conn @@ -65,8 +65,8 @@ func resource_aws_s3_bucket_destroy( } func resource_aws_s3_bucket_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) s3conn := p.s3conn @@ -80,7 +80,7 @@ func resource_aws_s3_bucket_refresh( } func resource_aws_s3_bucket_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { diff --git a/builtin/providers/aws/resource_aws_s3_bucket_test.go b/builtin/providers/aws/resource_aws_s3_bucket_test.go index 99b65ceae..09eed24aa 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket_test.go +++ b/builtin/providers/aws/resource_aws_s3_bucket_test.go @@ -27,12 +27,12 @@ func TestAccAWSS3Bucket(t *testing.T) { func testAccCheckAWSS3BucketDestroy(s *terraform.State) error { conn := testAccProvider.s3conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_s3_bucket" { continue } - bucket := conn.Bucket(rs.ID) + bucket := conn.Bucket(rs.Primary.ID) resp, err := bucket.Head("/") if err == nil { return fmt.Errorf("S3Bucket still exists") @@ -44,17 +44,17 @@ func testAccCheckAWSS3BucketDestroy(s *terraform.State) error { func testAccCheckAWSS3BucketExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No S3 Bucket ID is set") } conn := testAccProvider.s3conn - bucket := conn.Bucket(rs.ID) + bucket := conn.Bucket(rs.Primary.ID) resp, err := bucket.Head("/") if err != nil { return fmt.Errorf("S3Bucket error: %v", err) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index efc1e68ee..9e787d80f 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/ec2" ) @@ -271,8 +270,6 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro sg := sgRaw.(*ec2.SecurityGroupInfo) - var deps []terraform.ResourceDependency - // Gather our ingress rules ingressRules := make([]map[string]interface{}, len(sg.IPPerms)) for i, perm := range sg.IPPerms { @@ -286,31 +283,17 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro } if len(perm.SourceGroups) > 0 { - // We depend on other security groups - for _, v := range perm.SourceGroups { - deps = append(deps, - terraform.ResourceDependency{ID: v.Id}, - ) - } - n["security_groups"] = flattenSecurityGroups(perm.SourceGroups) } ingressRules[i] = n } - if v := d.Get("vpc_id"); v != nil && v.(string) != "" { - deps = append(deps, - terraform.ResourceDependency{ID: v.(string)}, - ) - } - d.Set("description", sg.Description) d.Set("name", sg.Name) d.Set("vpc_id", sg.VpcId) d.Set("owner_id", sg.OwnerId) d.Set("ingress", ingressRules) - d.SetDependencies(deps) return nil } diff --git a/builtin/providers/aws/resource_aws_security_group_test.go b/builtin/providers/aws/resource_aws_security_group_test.go index e65346180..abd66593a 100644 --- a/builtin/providers/aws/resource_aws_security_group_test.go +++ b/builtin/providers/aws/resource_aws_security_group_test.go @@ -131,22 +131,22 @@ func TestAccAWSSecurityGroup_Change(t *testing.T) { func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_security_group" { continue } sgs := []ec2.SecurityGroup{ ec2.SecurityGroup{ - Id: rs.ID, + Id: rs.Primary.ID, }, } // Retrieve our group resp, err := conn.SecurityGroups(sgs, nil) if err == nil { - if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.ID { - return fmt.Errorf("Security Group (%s) still exists.", rs.ID) + if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID { + return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) } return nil @@ -167,19 +167,19 @@ func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No Security Group is set") } conn := testAccProvider.ec2conn sgs := []ec2.SecurityGroup{ ec2.SecurityGroup{ - Id: rs.ID, + Id: rs.Primary.ID, }, } resp, err := conn.SecurityGroups(sgs, nil) @@ -187,7 +187,7 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) return err } - if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.ID { + if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID { *group = resp.Groups[0] diff --git a/builtin/providers/aws/resource_aws_subnet.go b/builtin/providers/aws/resource_aws_subnet.go index b31158cdf..1935108ff 100644 --- a/builtin/providers/aws/resource_aws_subnet.go +++ b/builtin/providers/aws/resource_aws_subnet.go @@ -12,9 +12,9 @@ import ( ) func resource_aws_subnet_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -60,16 +60,16 @@ func resource_aws_subnet_create( } func resource_aws_subnet_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { // This should never be called because we have no update-able // attributes panic("Update for subnet is not supported") } func resource_aws_subnet_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -102,8 +102,8 @@ func resource_aws_subnet_destroy( } func resource_aws_subnet_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -120,7 +120,7 @@ func resource_aws_subnet_refresh( } func resource_aws_subnet_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ @@ -139,17 +139,12 @@ func resource_aws_subnet_diff( } func resource_aws_subnet_update_state( - s *terraform.ResourceState, - subnet *ec2.Subnet) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + subnet *ec2.Subnet) (*terraform.InstanceState, error) { s.Attributes["availability_zone"] = subnet.AvailabilityZone s.Attributes["cidr_block"] = subnet.CidrBlock s.Attributes["vpc_id"] = subnet.VpcId - // We belong to a VPC - s.Dependencies = []terraform.ResourceDependency{ - terraform.ResourceDependency{ID: subnet.VpcId}, - } - return s, nil } diff --git a/builtin/providers/aws/resource_aws_subnet_test.go b/builtin/providers/aws/resource_aws_subnet_test.go index 5016149ad..99a97a5ae 100644 --- a/builtin/providers/aws/resource_aws_subnet_test.go +++ b/builtin/providers/aws/resource_aws_subnet_test.go @@ -40,14 +40,14 @@ func TestAccAWSSubnet(t *testing.T) { func testAccCheckSubnetDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_subnet" { continue } // Try to find the resource resp, err := conn.DescribeSubnets( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err == nil { if len(resp.Subnets) > 0 { return fmt.Errorf("still exist.") @@ -71,18 +71,18 @@ func testAccCheckSubnetDestroy(s *terraform.State) error { func testAccCheckSubnetExists(n string, v *ec2.Subnet) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } conn := testAccProvider.ec2conn resp, err := conn.DescribeSubnets( - []string{rs.ID}, ec2.NewFilter()) + []string{rs.Primary.ID}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_aws_vpc.go b/builtin/providers/aws/resource_aws_vpc.go index acb2b3002..5e449f44c 100644 --- a/builtin/providers/aws/resource_aws_vpc.go +++ b/builtin/providers/aws/resource_aws_vpc.go @@ -13,9 +13,9 @@ import ( ) func resource_aws_vpc_create( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -89,9 +89,9 @@ func resource_aws_vpc_create( } func resource_aws_vpc_update( - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn rs := s.MergeDiff(d) @@ -132,7 +132,7 @@ func resource_aws_vpc_update( } func resource_aws_vpc_destroy( - s *terraform.ResourceState, + s *terraform.InstanceState, meta interface{}) error { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -151,8 +151,8 @@ func resource_aws_vpc_destroy( } func resource_aws_vpc_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -180,7 +180,7 @@ func resource_aws_vpc_refresh( } func resource_aws_vpc_diff( - s *terraform.ResourceState, + s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ @@ -200,8 +200,8 @@ func resource_aws_vpc_diff( } func resource_aws_vpc_update_state( - s *terraform.ResourceState, - vpc *ec2.VPC) (*terraform.ResourceState, error) { + s *terraform.InstanceState, + vpc *ec2.VPC) (*terraform.InstanceState, error) { s.Attributes["cidr_block"] = vpc.CidrBlock return s, nil } diff --git a/builtin/providers/aws/resource_aws_vpc_test.go b/builtin/providers/aws/resource_aws_vpc_test.go index 853cbe916..44e91ca44 100644 --- a/builtin/providers/aws/resource_aws_vpc_test.go +++ b/builtin/providers/aws/resource_aws_vpc_test.go @@ -62,13 +62,13 @@ func TestAccVpcUpdate(t *testing.T) { func testAccCheckVpcDestroy(s *terraform.State) error { conn := testAccProvider.ec2conn - for _, rs := range s.Resources { + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_vpc" { continue } // Try to find the VPC - resp, err := conn.DescribeVpcs([]string{rs.ID}, ec2.NewFilter()) + resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter()) if err == nil { if len(resp.VPCs) > 0 { return fmt.Errorf("VPCs still exist.") @@ -102,17 +102,17 @@ func testAccCheckVpcCidr(vpc *ec2.VPC, expected string) resource.TestCheckFunc { func testAccCheckVpcExists(n string, vpc *ec2.VPC) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.Resources[n] + rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.ID == "" { + if rs.Primary.ID == "" { return fmt.Errorf("No VPC ID is set") } conn := testAccProvider.ec2conn - resp, err := conn.DescribeVpcs([]string{rs.ID}, ec2.NewFilter()) + resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter()) if err != nil { return err } diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index 5a71b4acc..ba1d5ab1d 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -91,32 +91,35 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { } func (p *ResourceProvider) Apply( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Apply(s, d) + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Apply(info, s, d) } - return resourceMap.Apply(s, d, p) + return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Diff(s, c) + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Diff(info, s, c) } - return resourceMap.Diff(s, c, p) + return resourceMap.Diff(info, s, c, p) } func (p *ResourceProvider) Refresh( - s *terraform.ResourceState) (*terraform.ResourceState, error) { - if _, ok := p.p.ResourcesMap[s.Type]; ok { - return p.p.Refresh(s) + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { + if _, ok := p.p.ResourcesMap[info.Type]; ok { + return p.p.Refresh(info, s) } - return resourceMap.Refresh(s, p) + return resourceMap.Refresh(info, s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { From cdad3036aedf77be067ef6a6a73927d6a1b6406d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 11:15:07 -0700 Subject: [PATCH 36/85] command: closer to compiling --- command/apply.go | 12 +++-- command/apply_test.go | 107 +++++++++++++++++++++++++-------------- command/command_test.go | 22 +++++++- command/format_state.go | 43 +++++++++------- command/hook_count.go | 4 +- command/hook_ui.go | 8 +-- command/output.go | 4 +- command/output_test.go | 43 ++++++++++++---- command/plan_test.go | 92 +++++++++++++++++++++++---------- command/refresh_test.go | 109 +++++++++------------------------------- command/show_test.go | 10 +--- 11 files changed, 254 insertions(+), 200 deletions(-) diff --git a/command/apply.go b/command/apply.go index a3d6f204e..611f2f250 100644 --- a/command/apply.go +++ b/command/apply.go @@ -182,14 +182,18 @@ func (c *ApplyCommand) Run(args []string) int { } // If we have outputs, then output those at the end. - if state != nil && len(state.Outputs) > 0 { + var outputs map[string]string + if state != nil { + outputs = state.RootModule().Outputs + } + if len(outputs) > 0 { outputBuf := new(bytes.Buffer) outputBuf.WriteString("[reset][bold][green]\nOutputs:\n\n") // Output the outputs in alphabetical order keyLen := 0 - keys := make([]string, 0, len(state.Outputs)) - for key, _ := range state.Outputs { + keys := make([]string, 0, len(outputs)) + for key, _ := range outputs { keys = append(keys, key) if len(key) > keyLen { keyLen = len(key) @@ -198,7 +202,7 @@ func (c *ApplyCommand) Run(args []string) int { sort.Strings(keys) for _, k := range keys { - v := state.Outputs[k] + v := outputs[k] outputBuf.WriteString(fmt.Sprintf( " %s%s = %s\n", diff --git a/command/apply_test.go b/command/apply_test.go index 5cd7b7da0..f45737c59 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -140,8 +140,9 @@ func TestApply_error(t *testing.T) { var lock sync.Mutex errored := false p.ApplyFn = func( - s *terraform.ResourceState, - d *terraform.ResourceDiff) (*terraform.ResourceState, error) { + info *terraform.InstanceInfo, + s *terraform.InstanceState, + d *terraform.ResourceDiff) (*terraform.InstanceState, error) { lock.Lock() defer lock.Unlock() @@ -150,10 +151,11 @@ func TestApply_error(t *testing.T) { return nil, fmt.Errorf("error") } - return &terraform.ResourceState{ID: "foo"}, nil + return &terraform.InstanceState{ID: "foo"}, nil } p.DiffFn = func( - *terraform.ResourceState, + *terraform.InstanceInfo, + *terraform.InstanceState, *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { return &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ @@ -189,7 +191,7 @@ func TestApply_error(t *testing.T) { if state == nil { t.Fatal("state should not be nil") } - if len(state.Resources) == 0 { + if len(state.RootModule().Resources) == 0 { t.Fatal("no resources in state") } } @@ -367,10 +369,17 @@ func TestApply_planVars(t *testing.T) { func TestApply_refresh(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -453,7 +462,8 @@ func TestApply_shutdown(t *testing.T) { } p.DiffFn = func( - *terraform.ResourceState, + *terraform.InstanceInfo, + *terraform.InstanceState, *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { return &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ @@ -464,15 +474,16 @@ func TestApply_shutdown(t *testing.T) { }, nil } p.ApplyFn = func( - *terraform.ResourceState, - *terraform.ResourceDiff) (*terraform.ResourceState, error) { + *terraform.InstanceInfo, + *terraform.InstanceState, + *terraform.ResourceDiff) (*terraform.InstanceState, error) { if !stopped { stopped = true close(stopCh) <-stopReplyCh } - return &terraform.ResourceState{ + return &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "ami": "2", @@ -518,18 +529,24 @@ func TestApply_shutdown(t *testing.T) { t.Fatal("state should not be nil") } - if len(state.Resources) != 1 { - t.Fatalf("bad: %d", len(state.Resources)) + if len(state.RootModule().Resources) != 1 { + t.Fatalf("bad: %d", len(state.RootModule().Resources)) } } func TestApply_state(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - ConnInfo: make(map[string]string), + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -563,7 +580,7 @@ func TestApply_state(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } @@ -604,7 +621,7 @@ func TestApply_state(t *testing.T) { } // nil out the ConnInfo since that should not be restored - originalState.Resources["test_instance.foo"].ConnInfo = nil + originalState.RootModule().Resources["test_instance.foo"].Primary.Ephemeral.ConnInfo = nil if !reflect.DeepEqual(backupState, originalState) { t.Fatalf("bad: %#v", backupState) @@ -644,7 +661,8 @@ func TestApply_vars(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -686,7 +704,8 @@ func TestApply_varFile(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -738,7 +757,8 @@ func TestApply_varFileDefault(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -762,10 +782,17 @@ func TestApply_varFileDefault(t *testing.T) { func TestApply_backup(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -831,8 +858,8 @@ func TestApply_backup(t *testing.T) { t.Fatalf("err: %s", err) } - actual := backupState.Resources["test_instance.foo"] - expected := originalState.Resources["test_instance.foo"] + actual := backupState.RootModule().Resources["test_instance.foo"] + expected := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v %#v", actual, expected) } @@ -840,11 +867,17 @@ func TestApply_backup(t *testing.T) { func TestApply_disableBackup(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - ConnInfo: make(map[string]string), + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -879,7 +912,7 @@ func TestApply_disableBackup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } diff --git a/command/command_test.go b/command/command_test.go index 09f8022f2..0acfa9f78 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -67,6 +67,25 @@ func testReadPlan(t *testing.T, path string) *terraform.Plan { return p } +// testState returns a test State structure that we use for a lot of tests. +func testState() *terraform.State { + return &terraform.State{ + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } +} + func testStateFile(t *testing.T, s *terraform.State) string { path := testTempFile(t) @@ -87,7 +106,8 @@ func testProvider() *terraform.MockResourceProvider { p := new(terraform.MockResourceProvider) p.DiffReturn = &terraform.ResourceDiff{} p.RefreshFn = func( - s *terraform.ResourceState) (*terraform.ResourceState, error) { + info *terraform.InstanceInfo, + s *terraform.InstanceState) (*terraform.InstanceState, error) { return s, nil } p.ResourcesReturn = []terraform.ResourceType{ diff --git a/command/format_state.go b/command/format_state.go index d21d036e9..90405042b 100644 --- a/command/format_state.go +++ b/command/format_state.go @@ -16,42 +16,49 @@ func FormatState(s *terraform.State, c *colorstring.Colorize) string { panic("colorize not given") } - if len(s.Resources) == 0 { + if len(s.Modules) == 0 { return "The state file is empty. No resources are represented." } - buf := new(bytes.Buffer) + var buf bytes.Buffer + for _, m := range s.Modules { + formatStateModule(&buf, m, c) + } + + return c.Color(strings.TrimSpace(buf.String())) +} + +func formatStateModule(buf *bytes.Buffer, m *terraform.ModuleState, c *colorstring.Colorize) { buf.WriteString("[reset]") // First get the names of all the resources so we can show them // in alphabetical order. - names := make([]string, 0, len(s.Resources)) - for name, _ := range s.Resources { + names := make([]string, 0, len(m.Resources)) + for name, _ := range m.Resources { names = append(names, name) } sort.Strings(names) // Go through each resource and begin building up the output. for _, k := range names { - rs := s.Resources[k] - id := rs.ID + rs := m.Resources[k] + is := rs.Primary + id := is.ID if id == "" { id = "" } taintStr := "" - if s.Tainted != nil { - if _, ok := s.Tainted[k]; ok { - taintStr = " (tainted)" - } + if len(rs.Tainted) > 0 { + taintStr = " (tainted)" } buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) buf.WriteString(fmt.Sprintf(" id = %s\n", id)) // Sort the attributes - attrKeys := make([]string, 0, len(rs.Attributes)) - for ak, _ := range rs.Attributes { + attrKeys := make([]string, 0, len(is.Attributes)) + for ak, _ := range is.Attributes { // Skip the id attribute since we just show the id directly if ak == "id" { continue @@ -63,27 +70,25 @@ func FormatState(s *terraform.State, c *colorstring.Colorize) string { // Output each attribute for _, ak := range attrKeys { - av := rs.Attributes[ak] + av := is.Attributes[ak] buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) } } - if len(s.Outputs) > 0 { + if len(m.Outputs) > 0 { buf.WriteString("\nOutputs:\n\n") // Sort the outputs - ks := make([]string, 0, len(s.Outputs)) - for k, _ := range s.Outputs { + ks := make([]string, 0, len(m.Outputs)) + for k, _ := range m.Outputs { ks = append(ks, k) } sort.Strings(ks) // Output each output k/v pair for _, k := range ks { - v := s.Outputs[k] + v := m.Outputs[k] buf.WriteString(fmt.Sprintf("%s = %s\n", k, v)) } } - - return c.Color(strings.TrimSpace(buf.String())) } diff --git a/command/hook_count.go b/command/hook_count.go index 152d3170e..bbebcc78c 100644 --- a/command/hook_count.go +++ b/command/hook_count.go @@ -39,7 +39,7 @@ func (h *CountHook) Reset() { func (h *CountHook) PreApply( id string, - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff) (terraform.HookAction, error) { h.Lock() defer h.Unlock() @@ -62,7 +62,7 @@ func (h *CountHook) PreApply( func (h *CountHook) PostApply( id string, - s *terraform.ResourceState, + s *terraform.InstanceState, e error) (terraform.HookAction, error) { h.Lock() defer h.Unlock() diff --git a/command/hook_ui.go b/command/hook_ui.go index 3b0771c80..8fe6e7c63 100644 --- a/command/hook_ui.go +++ b/command/hook_ui.go @@ -35,7 +35,7 @@ const ( func (h *UiHook) PreApply( id string, - s *terraform.ResourceState, + s *terraform.InstanceState, d *terraform.ResourceDiff) (terraform.HookAction, error) { h.once.Do(h.init) @@ -114,7 +114,7 @@ func (h *UiHook) PreApply( func (h *UiHook) PostApply( id string, - s *terraform.ResourceState, + s *terraform.InstanceState, applyerr error) (terraform.HookAction, error) { h.l.Lock() op := h.resources[id] @@ -145,7 +145,7 @@ func (h *UiHook) PostApply( } func (h *UiHook) PreDiff( - id string, s *terraform.ResourceState) (terraform.HookAction, error) { + id string, s *terraform.InstanceState) (terraform.HookAction, error) { return terraform.HookActionContinue, nil } @@ -157,7 +157,7 @@ func (h *UiHook) PreProvision(id, provId string) (terraform.HookAction, error) { } func (h *UiHook) PreRefresh( - id string, s *terraform.ResourceState) (terraform.HookAction, error) { + id string, s *terraform.InstanceState) (terraform.HookAction, error) { h.once.Do(h.init) h.ui.Output(h.Colorize.Color(fmt.Sprintf( diff --git a/command/output.go b/command/output.go index ab7292dd6..8e783d923 100644 --- a/command/output.go +++ b/command/output.go @@ -50,14 +50,14 @@ func (c *OutputCommand) Run(args []string) int { return 1 } - if len(state.Outputs) == 0 { + if len(state.RootModule().Outputs) == 0 { c.Ui.Error(fmt.Sprintf( "The state file has no outputs defined. Define an output\n" + "in your configuration with the `output` directive and re-run\n" + "`terraform apply` for it to become available.")) return 1 } - v, ok := state.Outputs[name] + v, ok := state.RootModule().Outputs[name] if !ok { c.Ui.Error(fmt.Sprintf( "The output variable requested could not be found in the state\n" + diff --git a/command/output_test.go b/command/output_test.go index f177198c5..5714ac20d 100644 --- a/command/output_test.go +++ b/command/output_test.go @@ -13,8 +13,13 @@ import ( func TestOutput(t *testing.T) { originalState := &terraform.State{ - Outputs: map[string]string{ - "foo": "bar", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]string{ + "foo": "bar", + }, + }, }, } @@ -44,8 +49,13 @@ func TestOutput(t *testing.T) { func TestOutput_badVar(t *testing.T) { originalState := &terraform.State{ - Outputs: map[string]string{ - "foo": "bar", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]string{ + "foo": "bar", + }, + }, }, } @@ -70,8 +80,13 @@ func TestOutput_badVar(t *testing.T) { func TestOutput_blank(t *testing.T) { originalState := &terraform.State{ - Outputs: map[string]string{ - "foo": "bar", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]string{ + "foo": "bar", + }, + }, }, } @@ -129,7 +144,12 @@ func TestOutput_noArgs(t *testing.T) { func TestOutput_noVars(t *testing.T) { originalState := &terraform.State{ - Outputs: map[string]string{}, + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]string{}, + }, + }, } statePath := testStateFile(t, originalState) @@ -153,8 +173,13 @@ func TestOutput_noVars(t *testing.T) { func TestOutput_stateDefault(t *testing.T) { originalState := &terraform.State{ - Outputs: map[string]string{ - "foo": "bar", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]string{ + "foo": "bar", + }, + }, }, } diff --git a/command/plan_test.go b/command/plan_test.go index af211cd2f..af4ab8cca 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -38,10 +38,17 @@ func TestPlan(t *testing.T) { func TestPlan_destroy(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -198,10 +205,17 @@ func TestPlan_state(t *testing.T) { defer os.Remove(tf.Name()) originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -230,7 +244,7 @@ func TestPlan_state(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } @@ -238,10 +252,17 @@ func TestPlan_state(t *testing.T) { func TestPlan_stateDefault(t *testing.T) { originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -291,7 +312,7 @@ func TestPlan_stateDefault(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } @@ -309,7 +330,8 @@ func TestPlan_vars(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -348,7 +370,8 @@ func TestPlan_varFile(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -397,7 +420,8 @@ func TestPlan_varFileDefault(t *testing.T) { actual := "" p.DiffFn = func( - s *terraform.ResourceState, + info *terraform.InstanceInfo, + s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) @@ -438,10 +462,17 @@ func TestPlan_backup(t *testing.T) { defer os.Remove(backupPath) originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -471,7 +502,7 @@ func TestPlan_backup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } @@ -503,10 +534,17 @@ func TestPlan_disableBackup(t *testing.T) { defer os.Remove(tf.Name()) originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", + Modules: []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, }, }, } @@ -536,7 +574,7 @@ func TestPlan_disableBackup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.Resources["test_instance.foo"] + expectedState := originalState.RootModule().Resources["test_instance.foo"] if !reflect.DeepEqual(p.DiffState, expectedState) { t.Fatalf("bad: %#v", p.DiffState) } diff --git a/command/refresh_test.go b/command/refresh_test.go index 145c4699a..073be20cd 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -12,14 +12,7 @@ import ( ) func TestRefresh(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) p := testProvider() @@ -32,7 +25,7 @@ func TestRefresh(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ "-state", statePath, @@ -57,7 +50,7 @@ func TestRefresh(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"] expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) @@ -93,14 +86,7 @@ func TestRefresh_cwd(t *testing.T) { } defer os.Chdir(cwd) - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) p := testProvider() @@ -113,7 +99,7 @@ func TestRefresh_cwd(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ "-state", statePath, @@ -137,7 +123,7 @@ func TestRefresh_cwd(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"] expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) @@ -145,14 +131,7 @@ func TestRefresh_cwd(t *testing.T) { } func TestRefresh_defaultState(t *testing.T) { - originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + originalState := testState() // Write the state file in a temporary directory with the // default filename. @@ -192,7 +171,7 @@ func TestRefresh_defaultState(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ testFixturePath("refresh"), @@ -216,7 +195,7 @@ func TestRefresh_defaultState(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"].Primary expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) @@ -233,22 +212,15 @@ func TestRefresh_defaultState(t *testing.T) { t.Fatalf("err: %s", err) } - actual = backupState.Resources["test_instance.foo"] - expected = originalState.Resources["test_instance.foo"] + actual = backupState.RootModule().Resources["test_instance.foo"].Primary + expected = originalState.RootModule().Resources["test_instance.foo"].Primary if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestRefresh_outPath(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) // Output path @@ -270,7 +242,7 @@ func TestRefresh_outPath(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ "-state", statePath, @@ -307,7 +279,7 @@ func TestRefresh_outPath(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"].Primary expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) @@ -330,14 +302,7 @@ func TestRefresh_outPath(t *testing.T) { } func TestRefresh_var(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) p := testProvider() @@ -367,14 +332,7 @@ func TestRefresh_var(t *testing.T) { } func TestRefresh_varFile(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) p := testProvider() @@ -409,14 +367,7 @@ func TestRefresh_varFile(t *testing.T) { } func TestRefresh_varFileDefault(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) p := testProvider() @@ -460,14 +411,7 @@ func TestRefresh_varFileDefault(t *testing.T) { } func TestRefresh_backup(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) // Output path @@ -498,7 +442,7 @@ func TestRefresh_backup(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ "-state", statePath, @@ -536,7 +480,7 @@ func TestRefresh_backup(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"].Primary expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) @@ -559,14 +503,7 @@ func TestRefresh_backup(t *testing.T) { } func TestRefresh_disableBackup(t *testing.T) { - state := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } + state := testState() statePath := testStateFile(t, state) // Output path @@ -588,7 +525,7 @@ func TestRefresh_disableBackup(t *testing.T) { } p.RefreshFn = nil - p.RefreshReturn = &terraform.ResourceState{ID: "yes"} + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} args := []string{ "-state", statePath, @@ -626,7 +563,7 @@ func TestRefresh_disableBackup(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.Resources["test_instance.foo"] + actual := newState.RootModule().Resources["test_instance.foo"].Primary expected := p.RefreshReturn if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) diff --git a/command/show_test.go b/command/show_test.go index c1bebf247..3025f258e 100644 --- a/command/show_test.go +++ b/command/show_test.go @@ -63,15 +63,7 @@ func TestShow_plan(t *testing.T) { } func TestShow_state(t *testing.T) { - originalState := &terraform.State{ - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - ID: "bar", - Type: "test_instance", - }, - }, - } - + originalState := testState() statePath := testStateFile(t, originalState) ui := new(cli.MockUi) From 0a6c675fbab4730de0f34be0b52db3b5062b05c5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 15:00:19 -0700 Subject: [PATCH 37/85] terraform: update hooks to use InstanceState --- terraform/context.go | 14 +++++++------- terraform/context_test.go | 6 ++++++ terraform/hook.go | 28 ++++++++++++++-------------- terraform/hook_mock.go | 32 ++++++++++++++++---------------- terraform/hook_stop.go | 14 +++++++------- terraform/terraform_test.go | 4 ++-- 6 files changed, 52 insertions(+), 46 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 73f9b94ed..f4fbd1fca 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -573,7 +573,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } for _, h := range c.hooks { - handleHook(h.PreApply(r.Id, r.State, diff)) + handleHook(h.PreApply(r.Id, r.State.Primary, diff)) } // With the completed diff, apply! @@ -631,7 +631,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { tainted := false if applyerr == nil && r.State.Primary.ID != "" && len(r.Provisioners) > 0 { for _, h := range c.hooks { - handleHook(h.PreProvisionResource(r.Id, r.State)) + handleHook(h.PreProvisionResource(r.Id, r.State.Primary)) } if err := c.applyProvisioners(r, is); err != nil { @@ -640,7 +640,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } for _, h := range c.hooks { - handleHook(h.PostProvisionResource(r.Id, r.State)) + handleHook(h.PostProvisionResource(r.Id, r.State.Primary)) } } @@ -656,7 +656,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { r.Tainted = tainted for _, h := range c.hooks { - handleHook(h.PostApply(r.Id, r.State, applyerr)) + handleHook(h.PostApply(r.Id, r.State.Primary, applyerr)) } // Determine the new state and update variables @@ -749,7 +749,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { var diff *ResourceDiff for _, h := range c.hooks { - handleHook(h.PreDiff(r.Id, r.State)) + handleHook(h.PreDiff(r.Id, r.State.Primary)) } if r.Config == nil { @@ -875,7 +875,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { } for _, h := range c.hooks { - handleHook(h.PreRefresh(r.Id, r.State)) + handleHook(h.PreRefresh(r.Id, r.State.Primary)) } info := &InstanceInfo{Type: r.State.Type} @@ -900,7 +900,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { c.sl.Unlock() for _, h := range c.hooks { - handleHook(h.PostRefresh(r.Id, r.State)) + handleHook(h.PostRefresh(r.Id, r.State.Primary)) } return nil diff --git a/terraform/context_test.go b/terraform/context_test.go index 9c1021711..6ef5706a1 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2111,15 +2111,21 @@ func TestContextRefresh_hook(t *testing.T) { if !h.PreRefreshCalled { t.Fatal("should be called") } + /* + TODO(mitchcellh): remove when we add InstanceInfo param if h.PreRefreshState.Type != "aws_instance" { t.Fatalf("bad: %#v", h.PreRefreshState) } + */ if !h.PostRefreshCalled { t.Fatal("should be called") } + /* + TODO(mitchcellh): remove when we add InstanceInfo param if h.PostRefreshState.Type != "aws_instance" { t.Fatalf("bad: %#v", h.PostRefreshState) } + */ } func TestContextRefresh_state(t *testing.T) { diff --git a/terraform/hook.go b/terraform/hook.go index 83b541422..fab4e7d65 100644 --- a/terraform/hook.go +++ b/terraform/hook.go @@ -24,24 +24,24 @@ type Hook interface { // PreApply and PostApply are called before and after a single // resource is applied. The error argument in PostApply is the // error, if any, that was returned from the provider Apply call itself. - PreApply(string, *ResourceState, *ResourceDiff) (HookAction, error) - PostApply(string, *ResourceState, error) (HookAction, error) + PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) + PostApply(string, *InstanceState, error) (HookAction, error) // PreDiff and PostDiff are called before and after a single resource // resource is diffed. - PreDiff(string, *ResourceState) (HookAction, error) + PreDiff(string, *InstanceState) (HookAction, error) PostDiff(string, *ResourceDiff) (HookAction, error) // Provisioning hooks - PreProvisionResource(string, *ResourceState) (HookAction, error) - PostProvisionResource(string, *ResourceState) (HookAction, error) + PreProvisionResource(string, *InstanceState) (HookAction, error) + PostProvisionResource(string, *InstanceState) (HookAction, error) PreProvision(string, string) (HookAction, error) PostProvision(string, string) (HookAction, error) // PreRefresh and PostRefresh are called before and after a single // resource state is refreshed, respectively. - PreRefresh(string, *ResourceState) (HookAction, error) - PostRefresh(string, *ResourceState) (HookAction, error) + PreRefresh(string, *InstanceState) (HookAction, error) + PostRefresh(string, *InstanceState) (HookAction, error) } // NilHook is a Hook implementation that does nothing. It exists only to @@ -49,15 +49,15 @@ type Hook interface { // and only implement the functions you are interested in. type NilHook struct{} -func (*NilHook) PreApply(string, *ResourceState, *ResourceDiff) (HookAction, error) { +func (*NilHook) PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostApply(string, *ResourceState, error) (HookAction, error) { +func (*NilHook) PostApply(string, *InstanceState, error) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PreDiff(string, *ResourceState) (HookAction, error) { +func (*NilHook) PreDiff(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } @@ -65,11 +65,11 @@ func (*NilHook) PostDiff(string, *ResourceDiff) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PreProvisionResource(string, *ResourceState) (HookAction, error) { +func (*NilHook) PreProvisionResource(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostProvisionResource(string, *ResourceState) (HookAction, error) { +func (*NilHook) PostProvisionResource(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } @@ -81,11 +81,11 @@ func (*NilHook) PostProvision(string, string) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PreRefresh(string, *ResourceState) (HookAction, error) { +func (*NilHook) PreRefresh(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostRefresh(string, *ResourceState) (HookAction, error) { +func (*NilHook) PostRefresh(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } diff --git a/terraform/hook_mock.go b/terraform/hook_mock.go index 344d35b6b..e991d495e 100644 --- a/terraform/hook_mock.go +++ b/terraform/hook_mock.go @@ -6,20 +6,20 @@ type MockHook struct { PreApplyCalled bool PreApplyId string PreApplyDiff *ResourceDiff - PreApplyState *ResourceState + PreApplyState *InstanceState PreApplyReturn HookAction PreApplyError error PostApplyCalled bool PostApplyId string - PostApplyState *ResourceState + PostApplyState *InstanceState PostApplyError error PostApplyReturn HookAction PostApplyReturnError error PreDiffCalled bool PreDiffId string - PreDiffState *ResourceState + PreDiffState *InstanceState PreDiffReturn HookAction PreDiffError error @@ -31,13 +31,13 @@ type MockHook struct { PreProvisionResourceCalled bool PreProvisionResourceId string - PreProvisionResourceState *ResourceState + PreProvisionInstanceState *InstanceState PreProvisionResourceReturn HookAction PreProvisionResourceError error PostProvisionResourceCalled bool PostProvisionResourceId string - PostProvisionResourceState *ResourceState + PostProvisionInstanceState *InstanceState PostProvisionResourceReturn HookAction PostProvisionResourceError error @@ -55,18 +55,18 @@ type MockHook struct { PostRefreshCalled bool PostRefreshId string - PostRefreshState *ResourceState + PostRefreshState *InstanceState PostRefreshReturn HookAction PostRefreshError error PreRefreshCalled bool PreRefreshId string - PreRefreshState *ResourceState + PreRefreshState *InstanceState PreRefreshReturn HookAction PreRefreshError error } -func (h *MockHook) PreApply(n string, s *ResourceState, d *ResourceDiff) (HookAction, error) { +func (h *MockHook) PreApply(n string, s *InstanceState, d *ResourceDiff) (HookAction, error) { h.PreApplyCalled = true h.PreApplyId = n h.PreApplyDiff = d @@ -74,7 +74,7 @@ func (h *MockHook) PreApply(n string, s *ResourceState, d *ResourceDiff) (HookAc return h.PreApplyReturn, h.PreApplyError } -func (h *MockHook) PostApply(n string, s *ResourceState, e error) (HookAction, error) { +func (h *MockHook) PostApply(n string, s *InstanceState, e error) (HookAction, error) { h.PostApplyCalled = true h.PostApplyId = n h.PostApplyState = s @@ -82,7 +82,7 @@ func (h *MockHook) PostApply(n string, s *ResourceState, e error) (HookAction, e return h.PostApplyReturn, h.PostApplyReturnError } -func (h *MockHook) PreDiff(n string, s *ResourceState) (HookAction, error) { +func (h *MockHook) PreDiff(n string, s *InstanceState) (HookAction, error) { h.PreDiffCalled = true h.PreDiffId = n h.PreDiffState = s @@ -96,17 +96,17 @@ func (h *MockHook) PostDiff(n string, d *ResourceDiff) (HookAction, error) { return h.PostDiffReturn, h.PostDiffError } -func (h *MockHook) PreProvisionResource(id string, s *ResourceState) (HookAction, error) { +func (h *MockHook) PreProvisionResource(id string, s *InstanceState) (HookAction, error) { h.PreProvisionResourceCalled = true h.PreProvisionResourceId = id - h.PreProvisionResourceState = s + h.PreProvisionInstanceState = s return h.PreProvisionResourceReturn, h.PreProvisionResourceError } -func (h *MockHook) PostProvisionResource(id string, s *ResourceState) (HookAction, error) { +func (h *MockHook) PostProvisionResource(id string, s *InstanceState) (HookAction, error) { h.PostProvisionResourceCalled = true h.PostProvisionResourceId = id - h.PostProvisionResourceState = s + h.PostProvisionInstanceState = s return h.PostProvisionResourceReturn, h.PostProvisionResourceError } @@ -124,14 +124,14 @@ func (h *MockHook) PostProvision(id, provId string) (HookAction, error) { return h.PostProvisionReturn, h.PostProvisionError } -func (h *MockHook) PreRefresh(n string, s *ResourceState) (HookAction, error) { +func (h *MockHook) PreRefresh(n string, s *InstanceState) (HookAction, error) { h.PreRefreshCalled = true h.PreRefreshId = n h.PreRefreshState = s return h.PreRefreshReturn, h.PreRefreshError } -func (h *MockHook) PostRefresh(n string, s *ResourceState) (HookAction, error) { +func (h *MockHook) PostRefresh(n string, s *InstanceState) (HookAction, error) { h.PostRefreshCalled = true h.PostRefreshId = n h.PostRefreshState = s diff --git a/terraform/hook_stop.go b/terraform/hook_stop.go index 5807f0cd3..4beda674d 100644 --- a/terraform/hook_stop.go +++ b/terraform/hook_stop.go @@ -10,15 +10,15 @@ type stopHook struct { stop uint32 } -func (h *stopHook) PreApply(string, *ResourceState, *ResourceDiff) (HookAction, error) { +func (h *stopHook) PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) { return h.hook() } -func (h *stopHook) PostApply(string, *ResourceState, error) (HookAction, error) { +func (h *stopHook) PostApply(string, *InstanceState, error) (HookAction, error) { return h.hook() } -func (h *stopHook) PreDiff(string, *ResourceState) (HookAction, error) { +func (h *stopHook) PreDiff(string, *InstanceState) (HookAction, error) { return h.hook() } @@ -26,11 +26,11 @@ func (h *stopHook) PostDiff(string, *ResourceDiff) (HookAction, error) { return h.hook() } -func (h *stopHook) PreProvisionResource(string, *ResourceState) (HookAction, error) { +func (h *stopHook) PreProvisionResource(string, *InstanceState) (HookAction, error) { return h.hook() } -func (h *stopHook) PostProvisionResource(string, *ResourceState) (HookAction, error) { +func (h *stopHook) PostProvisionResource(string, *InstanceState) (HookAction, error) { return h.hook() } @@ -42,11 +42,11 @@ func (h *stopHook) PostProvision(string, string) (HookAction, error) { return h.hook() } -func (h *stopHook) PreRefresh(string, *ResourceState) (HookAction, error) { +func (h *stopHook) PreRefresh(string, *InstanceState) (HookAction, error) { return h.hook() } -func (h *stopHook) PostRefresh(string, *ResourceState) (HookAction, error) { +func (h *stopHook) PostRefresh(string, *InstanceState) (HookAction, error) { return h.hook() } diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 7d89c3948..75fc36c60 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -59,7 +59,7 @@ type HookRecordApplyOrder struct { Active bool IDs []string - States []*ResourceState + States []*InstanceState Diffs []*ResourceDiff l sync.Mutex @@ -67,7 +67,7 @@ type HookRecordApplyOrder struct { func (h *HookRecordApplyOrder) PreApply( id string, - s *ResourceState, + s *InstanceState, d *ResourceDiff) (HookAction, error) { if h.Active { h.l.Lock() From 9b2b3a963f741d72b515cec112a1c9a3eabc14e5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 16:33:24 -0700 Subject: [PATCH 38/85] ResourceDiff => InstanceDiff --- .../aws/resource_aws_autoscaling_group.go | 6 +- .../providers/aws/resource_aws_db_instance.go | 6 +- .../aws/resource_aws_db_security_group.go | 6 +- builtin/providers/aws/resource_aws_elb.go | 6 +- .../aws/resource_aws_internet_gateway.go | 6 +- .../aws/resource_aws_launch_configuration.go | 6 +- .../aws/resource_aws_route53_record.go | 4 +- .../aws/resource_aws_route53_zone.go | 4 +- .../providers/aws/resource_aws_route_table.go | 6 +- .../resource_aws_route_table_association.go | 6 +- .../providers/aws/resource_aws_s3_bucket.go | 4 +- builtin/providers/aws/resource_aws_subnet.go | 6 +- builtin/providers/aws/resource_aws_vpc.go | 6 +- builtin/providers/aws/resource_provider.go | 4 +- .../cloudflare/resource_cloudflare_record.go | 6 +- .../providers/cloudflare/resource_provider.go | 4 +- .../providers/consul/resource_consul_keys.go | 6 +- builtin/providers/consul/resource_provider.go | 4 +- .../resource_digitalocean_droplet.go | 6 +- .../digitalocean/resource_provider.go | 4 +- .../dnsimple/resource_dnsimple_record.go | 6 +- .../providers/dnsimple/resource_provider.go | 4 +- command/apply_test.go | 30 ++++---- command/command_test.go | 2 +- command/hook_count.go | 2 +- command/hook_ui.go | 2 +- command/output_test.go | 2 +- command/plan_test.go | 8 +-- helper/diff/diff_test.go | 2 +- helper/diff/resource_builder.go | 6 +- helper/resource/map.go | 4 +- helper/resource/resource.go | 6 +- helper/resource/testing_test.go | 2 +- helper/schema/provider.go | 4 +- helper/schema/resource.go | 4 +- helper/schema/resource_data.go | 2 +- helper/schema/resource_data_test.go | 66 ++++++++--------- helper/schema/resource_test.go | 10 +-- helper/schema/schema.go | 18 ++--- helper/schema/schema_test.go | 48 ++++++------- rpc/resource_provider.go | 16 ++--- rpc/resource_provider_test.go | 4 +- terraform/context.go | 8 +-- terraform/context_test.go | 70 +++++++++---------- terraform/diff.go | 18 ++--- terraform/diff_test.go | 50 ++++++------- terraform/graph.go | 4 +- terraform/graph_test.go | 12 ++-- terraform/hook.go | 8 +-- terraform/hook_mock.go | 8 +-- terraform/hook_stop.go | 4 +- terraform/plan_test.go | 4 +- terraform/resource.go | 2 +- terraform/resource_provider.go | 4 +- terraform/resource_provider_mock.go | 12 ++-- terraform/state.go | 2 +- terraform/state_test.go | 4 +- terraform/state_v1.go | 2 +- terraform/terraform_test.go | 4 +- 59 files changed, 285 insertions(+), 285 deletions(-) diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index 4bd807f41..f41608d76 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -14,7 +14,7 @@ import ( func resource_aws_autoscaling_group_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -94,7 +94,7 @@ func resource_aws_autoscaling_group_create( func resource_aws_autoscaling_group_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -187,7 +187,7 @@ func resource_aws_autoscaling_group_refresh( func resource_aws_autoscaling_group_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_db_instance.go b/builtin/providers/aws/resource_aws_db_instance.go index 79a716992..63d0402f2 100644 --- a/builtin/providers/aws/resource_aws_db_instance.go +++ b/builtin/providers/aws/resource_aws_db_instance.go @@ -17,7 +17,7 @@ import ( func resource_aws_db_instance_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -137,7 +137,7 @@ func resource_aws_db_instance_create( func resource_aws_db_instance_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { panic("Cannot update DB") } @@ -201,7 +201,7 @@ func resource_aws_db_instance_refresh( func resource_aws_db_instance_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_db_security_group.go b/builtin/providers/aws/resource_aws_db_security_group.go index d9eacd9ac..a4cb1c308 100644 --- a/builtin/providers/aws/resource_aws_db_security_group.go +++ b/builtin/providers/aws/resource_aws_db_security_group.go @@ -16,7 +16,7 @@ import ( func resource_aws_db_security_group_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn @@ -86,7 +86,7 @@ func resource_aws_db_security_group_create( func resource_aws_db_security_group_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { panic("Cannot update DB security group") } @@ -133,7 +133,7 @@ func resource_aws_db_security_group_refresh( func resource_aws_db_security_group_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 5fd512a77..90c0b9ff7 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -14,7 +14,7 @@ import ( func resource_aws_elb_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -125,7 +125,7 @@ func resource_aws_elb_create( func resource_aws_elb_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn @@ -251,7 +251,7 @@ func resource_aws_elb_refresh( func resource_aws_elb_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_internet_gateway.go b/builtin/providers/aws/resource_aws_internet_gateway.go index 9a60d0333..a13892c60 100644 --- a/builtin/providers/aws/resource_aws_internet_gateway.go +++ b/builtin/providers/aws/resource_aws_internet_gateway.go @@ -13,7 +13,7 @@ import ( func resource_aws_internet_gateway_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -36,7 +36,7 @@ func resource_aws_internet_gateway_create( func resource_aws_internet_gateway_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -128,7 +128,7 @@ func resource_aws_internet_gateway_refresh( func resource_aws_internet_gateway_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "vpc_id": diff.AttrTypeUpdate, diff --git a/builtin/providers/aws/resource_aws_launch_configuration.go b/builtin/providers/aws/resource_aws_launch_configuration.go index 6e39aa53c..c68320bb6 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration.go +++ b/builtin/providers/aws/resource_aws_launch_configuration.go @@ -13,7 +13,7 @@ import ( func resource_aws_launch_configuration_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn @@ -76,7 +76,7 @@ func resource_aws_launch_configuration_create( func resource_aws_launch_configuration_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { panic("Update for AWS Launch Configuration is not supported") } @@ -120,7 +120,7 @@ func resource_aws_launch_configuration_refresh( func resource_aws_launch_configuration_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_route53_record.go b/builtin/providers/aws/resource_aws_route53_record.go index da530ba34..60ff8df2a 100644 --- a/builtin/providers/aws/resource_aws_route53_record.go +++ b/builtin/providers/aws/resource_aws_route53_record.go @@ -29,7 +29,7 @@ func resource_aws_r53_record_validation() *config.Validator { func resource_aws_r53_record_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) conn := p.route53 @@ -234,7 +234,7 @@ func resource_aws_r53_record_update_state( func resource_aws_r53_record_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "zone_id": diff.AttrTypeCreate, diff --git a/builtin/providers/aws/resource_aws_route53_zone.go b/builtin/providers/aws/resource_aws_route53_zone.go index ef93da00f..6b68cf3cf 100644 --- a/builtin/providers/aws/resource_aws_route53_zone.go +++ b/builtin/providers/aws/resource_aws_route53_zone.go @@ -22,7 +22,7 @@ func resource_aws_r53_zone_validation() *config.Validator { func resource_aws_r53_zone_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) r53 := p.route53 @@ -109,7 +109,7 @@ func resource_aws_r53_zone_refresh( func resource_aws_r53_zone_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index 46249a347..b444a083c 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -15,7 +15,7 @@ import ( func resource_aws_route_table_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -57,7 +57,7 @@ func resource_aws_route_table_create( func resource_aws_route_table_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -208,7 +208,7 @@ func resource_aws_route_table_refresh( func resource_aws_route_table_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "vpc_id": diff.AttrTypeCreate, diff --git a/builtin/providers/aws/resource_aws_route_table_association.go b/builtin/providers/aws/resource_aws_route_table_association.go index 3d1b53c6d..c8932f749 100644 --- a/builtin/providers/aws/resource_aws_route_table_association.go +++ b/builtin/providers/aws/resource_aws_route_table_association.go @@ -11,7 +11,7 @@ import ( func resource_aws_route_table_association_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -37,7 +37,7 @@ func resource_aws_route_table_association_create( func resource_aws_route_table_association_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -122,7 +122,7 @@ func resource_aws_route_table_association_refresh( func resource_aws_route_table_association_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "subnet_id": diff.AttrTypeCreate, diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index 2d9d184a8..36a9f4f0f 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -23,7 +23,7 @@ func resource_aws_s3_bucket_validation() *config.Validator { func resource_aws_s3_bucket_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) s3conn := p.s3conn @@ -82,7 +82,7 @@ func resource_aws_s3_bucket_refresh( func resource_aws_s3_bucket_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/aws/resource_aws_subnet.go b/builtin/providers/aws/resource_aws_subnet.go index 1935108ff..e964e123e 100644 --- a/builtin/providers/aws/resource_aws_subnet.go +++ b/builtin/providers/aws/resource_aws_subnet.go @@ -13,7 +13,7 @@ import ( func resource_aws_subnet_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -61,7 +61,7 @@ func resource_aws_subnet_create( func resource_aws_subnet_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { // This should never be called because we have no update-able // attributes @@ -122,7 +122,7 @@ func resource_aws_subnet_refresh( func resource_aws_subnet_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "availability_zone": diff.AttrTypeCreate, diff --git a/builtin/providers/aws/resource_aws_vpc.go b/builtin/providers/aws/resource_aws_vpc.go index 5e449f44c..91c5dcfe2 100644 --- a/builtin/providers/aws/resource_aws_vpc.go +++ b/builtin/providers/aws/resource_aws_vpc.go @@ -14,7 +14,7 @@ import ( func resource_aws_vpc_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -90,7 +90,7 @@ func resource_aws_vpc_create( func resource_aws_vpc_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn @@ -182,7 +182,7 @@ func resource_aws_vpc_refresh( func resource_aws_vpc_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "cidr_block": diff.AttrTypeCreate, diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index ba1d5ab1d..b2c2fa1d8 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -93,7 +93,7 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { if _, ok := p.p.ResourcesMap[info.Type]; ok { return p.p.Apply(info, s, d) } @@ -104,7 +104,7 @@ func (p *ResourceProvider) Apply( func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if _, ok := p.p.ResourcesMap[info.Type]; ok { return p.p.Diff(info, s, c) } diff --git a/builtin/providers/cloudflare/resource_cloudflare_record.go b/builtin/providers/cloudflare/resource_cloudflare_record.go index f03905490..8f9b964a5 100644 --- a/builtin/providers/cloudflare/resource_cloudflare_record.go +++ b/builtin/providers/cloudflare/resource_cloudflare_record.go @@ -12,7 +12,7 @@ import ( func resource_cloudflare_record_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -52,7 +52,7 @@ func resource_cloudflare_record_create( func resource_cloudflare_record_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -119,7 +119,7 @@ func resource_cloudflare_record_refresh( func resource_cloudflare_record_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/cloudflare/resource_provider.go b/builtin/providers/cloudflare/resource_provider.go index ce1dcdc31..bb0dc0c6a 100644 --- a/builtin/providers/cloudflare/resource_provider.go +++ b/builtin/providers/cloudflare/resource_provider.go @@ -49,14 +49,14 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { return resourceMap.Diff(info, s, c, p) } diff --git a/builtin/providers/consul/resource_consul_keys.go b/builtin/providers/consul/resource_consul_keys.go index 36ef6ea59..12da4747b 100644 --- a/builtin/providers/consul/resource_consul_keys.go +++ b/builtin/providers/consul/resource_consul_keys.go @@ -28,14 +28,14 @@ func resource_consul_keys_validation() *config.Validator { } func resource_consul_keys_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { return resource_consul_keys_create(s, d, meta) } func resource_consul_keys_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) @@ -134,7 +134,7 @@ func resource_consul_keys_destroy( func resource_consul_keys_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { // Determine the list of computed variables var computed []string diff --git a/builtin/providers/consul/resource_provider.go b/builtin/providers/consul/resource_provider.go index fc20caa49..17da5a55c 100644 --- a/builtin/providers/consul/resource_provider.go +++ b/builtin/providers/consul/resource_provider.go @@ -45,14 +45,14 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { return resourceMap.Diff(info, s, c, p) } diff --git a/builtin/providers/digitalocean/resource_digitalocean_droplet.go b/builtin/providers/digitalocean/resource_digitalocean_droplet.go index c55538582..712f94a82 100644 --- a/builtin/providers/digitalocean/resource_digitalocean_droplet.go +++ b/builtin/providers/digitalocean/resource_digitalocean_droplet.go @@ -16,7 +16,7 @@ import ( func resource_digitalocean_droplet_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -91,7 +91,7 @@ func resource_digitalocean_droplet_create( func resource_digitalocean_droplet_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -238,7 +238,7 @@ func resource_digitalocean_droplet_refresh( func resource_digitalocean_droplet_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/digitalocean/resource_provider.go b/builtin/providers/digitalocean/resource_provider.go index d4bcd8798..30310711b 100644 --- a/builtin/providers/digitalocean/resource_provider.go +++ b/builtin/providers/digitalocean/resource_provider.go @@ -57,7 +57,7 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { if _, ok := p.p.ResourcesMap[info.Type]; ok { return p.p.Apply(info, s, d) } @@ -68,7 +68,7 @@ func (p *ResourceProvider) Apply( func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if _, ok := p.p.ResourcesMap[info.Type]; ok { return p.p.Diff(info, s, c) } diff --git a/builtin/providers/dnsimple/resource_dnsimple_record.go b/builtin/providers/dnsimple/resource_dnsimple_record.go index 10455e032..36b0a058a 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record.go @@ -12,7 +12,7 @@ import ( func resource_dnsimple_record_create( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -54,7 +54,7 @@ func resource_dnsimple_record_create( func resource_dnsimple_record_update( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { p := meta.(*ResourceProvider) client := p.client @@ -127,7 +127,7 @@ func resource_dnsimple_record_refresh( func resource_dnsimple_record_diff( s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ diff --git a/builtin/providers/dnsimple/resource_provider.go b/builtin/providers/dnsimple/resource_provider.go index 866271656..25a9ebb7c 100644 --- a/builtin/providers/dnsimple/resource_provider.go +++ b/builtin/providers/dnsimple/resource_provider.go @@ -49,14 +49,14 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { return resourceMap.Apply(info, s, d, p) } func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { return resourceMap.Diff(info, s, c, p) } diff --git a/command/apply_test.go b/command/apply_test.go index f45737c59..f6402ae44 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -142,7 +142,7 @@ func TestApply_error(t *testing.T) { p.ApplyFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { lock.Lock() defer lock.Unlock() @@ -156,8 +156,8 @@ func TestApply_error(t *testing.T) { p.DiffFn = func( *terraform.InstanceInfo, *terraform.InstanceState, - *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - return &terraform.ResourceDiff{ + *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { + return &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ami": &terraform.ResourceAttrDiff{ New: "bar", @@ -464,8 +464,8 @@ func TestApply_shutdown(t *testing.T) { p.DiffFn = func( *terraform.InstanceInfo, *terraform.InstanceState, - *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - return &terraform.ResourceDiff{ + *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { + return &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ami": &terraform.ResourceAttrDiff{ New: "bar", @@ -476,7 +476,7 @@ func TestApply_shutdown(t *testing.T) { p.ApplyFn = func( *terraform.InstanceInfo, *terraform.InstanceState, - *terraform.ResourceDiff) (*terraform.InstanceState, error) { + *terraform.InstanceDiff) (*terraform.InstanceState, error) { if !stopped { stopped = true close(stopCh) @@ -554,7 +554,7 @@ func TestApply_state(t *testing.T) { statePath := testStateFile(t, originalState) p := testProvider() - p.DiffReturn = &terraform.ResourceDiff{ + p.DiffReturn = &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ami": &terraform.ResourceAttrDiff{ New: "bar", @@ -663,12 +663,12 @@ func TestApply_vars(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } - return &terraform.ResourceDiff{}, nil + return &terraform.InstanceDiff{}, nil } args := []string{ @@ -706,12 +706,12 @@ func TestApply_varFile(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } - return &terraform.ResourceDiff{}, nil + return &terraform.InstanceDiff{}, nil } args := []string{ @@ -759,12 +759,12 @@ func TestApply_varFileDefault(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } - return &terraform.ResourceDiff{}, nil + return &terraform.InstanceDiff{}, nil } args := []string{ @@ -801,7 +801,7 @@ func TestApply_backup(t *testing.T) { backupPath := testTempFile(t) p := testProvider() - p.DiffReturn = &terraform.ResourceDiff{ + p.DiffReturn = &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ami": &terraform.ResourceAttrDiff{ New: "bar", @@ -885,7 +885,7 @@ func TestApply_disableBackup(t *testing.T) { statePath := testStateFile(t, originalState) p := testProvider() - p.DiffReturn = &terraform.ResourceDiff{ + p.DiffReturn = &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ami": &terraform.ResourceAttrDiff{ New: "bar", diff --git a/command/command_test.go b/command/command_test.go index 0acfa9f78..8d994ff72 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -104,7 +104,7 @@ func testStateFile(t *testing.T, s *terraform.State) string { func testProvider() *terraform.MockResourceProvider { p := new(terraform.MockResourceProvider) - p.DiffReturn = &terraform.ResourceDiff{} + p.DiffReturn = &terraform.InstanceDiff{} p.RefreshFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState) (*terraform.InstanceState, error) { diff --git a/command/hook_count.go b/command/hook_count.go index bbebcc78c..08dd98fd7 100644 --- a/command/hook_count.go +++ b/command/hook_count.go @@ -40,7 +40,7 @@ func (h *CountHook) Reset() { func (h *CountHook) PreApply( id string, s *terraform.InstanceState, - d *terraform.ResourceDiff) (terraform.HookAction, error) { + d *terraform.InstanceDiff) (terraform.HookAction, error) { h.Lock() defer h.Unlock() diff --git a/command/hook_ui.go b/command/hook_ui.go index 8fe6e7c63..16c1d7507 100644 --- a/command/hook_ui.go +++ b/command/hook_ui.go @@ -36,7 +36,7 @@ const ( func (h *UiHook) PreApply( id string, s *terraform.InstanceState, - d *terraform.ResourceDiff) (terraform.HookAction, error) { + d *terraform.InstanceDiff) (terraform.HookAction, error) { h.once.Do(h.init) op := uiResourceModify diff --git a/command/output_test.go b/command/output_test.go index 5714ac20d..fbcda9962 100644 --- a/command/output_test.go +++ b/command/output_test.go @@ -146,7 +146,7 @@ func TestOutput_noVars(t *testing.T) { originalState := &terraform.State{ Modules: []*terraform.ModuleState{ &terraform.ModuleState{ - Path: []string{"root"}, + Path: []string{"root"}, Outputs: map[string]string{}, }, }, diff --git a/command/plan_test.go b/command/plan_test.go index af4ab8cca..2f9ec37e2 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -149,7 +149,7 @@ func TestPlan_outPath(t *testing.T) { }, } - p.DiffReturn = &terraform.ResourceDiff{ + p.DiffReturn = &terraform.InstanceDiff{ Destroy: true, } @@ -332,7 +332,7 @@ func TestPlan_vars(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } @@ -372,7 +372,7 @@ func TestPlan_varFile(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } @@ -422,7 +422,7 @@ func TestPlan_varFileDefault(t *testing.T) { p.DiffFn = func( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { if v, ok := c.Config["value"]; ok { actual = v.(string) } diff --git a/helper/diff/diff_test.go b/helper/diff/diff_test.go index 4df4652f2..4509ff50a 100644 --- a/helper/diff/diff_test.go +++ b/helper/diff/diff_test.go @@ -29,7 +29,7 @@ func testConfig( return terraform.NewResourceConfig(rc) } -func testResourceDiffStr(rd *terraform.ResourceDiff) string { +func testResourceDiffStr(rd *terraform.InstanceDiff) string { var buf bytes.Buffer crud := "UPDATE" diff --git a/helper/diff/resource_builder.go b/helper/diff/resource_builder.go index e0516a6d8..18d010017 100644 --- a/helper/diff/resource_builder.go +++ b/helper/diff/resource_builder.go @@ -62,7 +62,7 @@ type PreProcessFunc func(string) string // configuration. func (b *ResourceBuilder) Diff( s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { attrs := make(map[string]*terraform.ResourceAttrDiff) // We require a new resource if the ID is empty. Or, later, we set @@ -207,9 +207,9 @@ func (b *ResourceBuilder) Diff( } // Build our resulting diff if we had attributes change - var result *terraform.ResourceDiff + var result *terraform.InstanceDiff if len(attrs) > 0 { - result = &terraform.ResourceDiff{ + result = &terraform.InstanceDiff{ Attributes: attrs, } } diff --git a/helper/resource/map.go b/helper/resource/map.go index 979791828..a465136f7 100644 --- a/helper/resource/map.go +++ b/helper/resource/map.go @@ -33,7 +33,7 @@ func (m *Map) Validate( func (m *Map) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { r, ok := m.Mapping[info.Type] if !ok { @@ -87,7 +87,7 @@ func (m *Map) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { + meta interface{}) (*terraform.InstanceDiff, error) { r, ok := m.Mapping[info.Type] if !ok { return nil, fmt.Errorf("Unknown resource type: %s", info.Type) diff --git a/helper/resource/resource.go b/helper/resource/resource.go index 60a56a31d..0d9c831a6 100644 --- a/helper/resource/resource.go +++ b/helper/resource/resource.go @@ -18,7 +18,7 @@ type Resource struct { // exist. type CreateFunc func( *terraform.InstanceState, - *terraform.ResourceDiff, + *terraform.InstanceDiff, interface{}) (*terraform.InstanceState, error) // DestroyFunc is a function that destroys a resource that previously @@ -31,7 +31,7 @@ type DestroyFunc func( type DiffFunc func( *terraform.InstanceState, *terraform.ResourceConfig, - interface{}) (*terraform.ResourceDiff, error) + interface{}) (*terraform.InstanceDiff, error) // RefreshFunc is a function that performs a refresh of a specific type // of resource. @@ -45,5 +45,5 @@ type RefreshFunc func( // a new resource. type UpdateFunc func( *terraform.InstanceState, - *terraform.ResourceDiff, + *terraform.InstanceDiff, interface{}) (*terraform.InstanceState, error) diff --git a/helper/resource/testing_test.go b/helper/resource/testing_test.go index ad00f79cc..cf51c7b22 100644 --- a/helper/resource/testing_test.go +++ b/helper/resource/testing_test.go @@ -261,7 +261,7 @@ func (t *mockT) failMessage() string { func testProvider() *terraform.MockResourceProvider { mp := new(terraform.MockResourceProvider) - mp.DiffReturn = &terraform.ResourceDiff{ + mp.DiffReturn = &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "bar", diff --git a/helper/schema/provider.go b/helper/schema/provider.go index 17f27e8e9..b1bb65ccb 100644 --- a/helper/schema/provider.go +++ b/helper/schema/provider.go @@ -138,7 +138,7 @@ func (p *Provider) Configure(c *terraform.ResourceConfig) error { func (p *Provider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { r, ok := p.ResourcesMap[info.Type] if !ok { return nil, fmt.Errorf("unknown resource type: %s", info.Type) @@ -151,7 +151,7 @@ func (p *Provider) Apply( func (p *Provider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { r, ok := p.ResourcesMap[info.Type] if !ok { return nil, fmt.Errorf("unknown resource type: %s", info.Type) diff --git a/helper/schema/resource.go b/helper/schema/resource.go index e9661c454..16c49f230 100644 --- a/helper/schema/resource.go +++ b/helper/schema/resource.go @@ -62,7 +62,7 @@ type DeleteFunc func(*ResourceData, interface{}) error // Apply creates, updates, and/or deletes a resource. func (r *Resource) Apply( s *terraform.InstanceState, - d *terraform.ResourceDiff, + d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { data, err := schemaMap(r.Schema).Data(s, d) if err != nil { @@ -112,7 +112,7 @@ func (r *Resource) Apply( // ResourceProvider interface. func (r *Resource) Diff( s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { return schemaMap(r.Schema).Diff(s, c) } diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index 5fbb0d4ea..e22c6e10d 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -24,7 +24,7 @@ type ResourceData struct { schema map[string]*Schema config *terraform.ResourceConfig state *terraform.InstanceState - diff *terraform.ResourceDiff + diff *terraform.InstanceDiff diffing bool // Don't set diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index 66397dd6a..3f4c9ed9c 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -11,7 +11,7 @@ func TestResourceDataGet(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Key string Value interface{} }{ @@ -27,7 +27,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "foo", @@ -53,7 +53,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -80,7 +80,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -133,7 +133,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "foo", @@ -273,7 +273,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "", @@ -311,7 +311,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "", @@ -366,7 +366,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -398,7 +398,7 @@ func TestResourceDataGet(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "0", @@ -482,7 +482,7 @@ func TestResourceDataGet(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -550,7 +550,7 @@ func TestResourceDataGetChange(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Key string OldValue interface{} NewValue interface{} @@ -567,7 +567,7 @@ func TestResourceDataGetChange(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -599,7 +599,7 @@ func TestResourceDataGetChange(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -636,7 +636,7 @@ func TestResourceDataGetOk(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Key string Value interface{} Ok bool @@ -656,7 +656,7 @@ func TestResourceDataGetOk(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -799,7 +799,7 @@ func TestResourceDataHasChange(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Key string Change bool }{ @@ -815,7 +815,7 @@ func TestResourceDataHasChange(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -846,7 +846,7 @@ func TestResourceDataHasChange(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -879,7 +879,7 @@ func TestResourceDataSet(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Key string Value interface{} Err bool @@ -1395,7 +1395,7 @@ func TestResourceDataState(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Set map[string]interface{} Result *terraform.InstanceState Partial []string @@ -1413,7 +1413,7 @@ func TestResourceDataState(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -1443,7 +1443,7 @@ func TestResourceDataState(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -1500,7 +1500,7 @@ func TestResourceDataState(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -1534,7 +1534,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -1580,7 +1580,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -1628,7 +1628,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.0.bar": &terraform.ResourceAttrDiff{ NewRemoved: true, @@ -1671,7 +1671,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -1707,7 +1707,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -1777,7 +1777,7 @@ func TestResourceDataState(t *testing.T) { State: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -1811,7 +1811,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -1858,7 +1858,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -1907,7 +1907,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.0.bar": &terraform.ResourceAttrDiff{ NewRemoved: true, @@ -1956,7 +1956,7 @@ func TestResourceDataState(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.1": &terraform.ResourceAttrDiff{ New: "120", diff --git a/helper/schema/resource_test.go b/helper/schema/resource_test.go index ad4ba5fb6..32ad34454 100644 --- a/helper/schema/resource_test.go +++ b/helper/schema/resource_test.go @@ -27,7 +27,7 @@ func TestResourceApply_create(t *testing.T) { var s *terraform.InstanceState = nil - d := &terraform.ResourceDiff{ + d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "42", @@ -77,7 +77,7 @@ func TestResourceApply_destroy(t *testing.T) { ID: "bar", } - d := &terraform.ResourceDiff{ + d := &terraform.InstanceDiff{ Destroy: true, } @@ -117,7 +117,7 @@ func TestResourceApply_destroyPartial(t *testing.T) { }, } - d := &terraform.ResourceDiff{ + d := &terraform.InstanceDiff{ Destroy: true, } @@ -161,7 +161,7 @@ func TestResourceApply_update(t *testing.T) { }, } - d := &terraform.ResourceDiff{ + d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "13", @@ -206,7 +206,7 @@ func TestResourceApply_updateNoCallback(t *testing.T) { }, } - d := &terraform.ResourceDiff{ + d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "13", diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 39d622d22..711262bf9 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -163,7 +163,7 @@ type schemaMap map[string]*Schema // The diff is optional. func (m schemaMap) Data( s *terraform.InstanceState, - d *terraform.ResourceDiff) (*ResourceData, error) { + d *terraform.InstanceDiff) (*ResourceData, error) { return &ResourceData{ schema: m, state: s, @@ -175,8 +175,8 @@ func (m schemaMap) Data( // state, and configuration. func (m schemaMap) Diff( s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { - result := new(terraform.ResourceDiff) + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { + result := new(terraform.InstanceDiff) result.Attributes = make(map[string]*terraform.ResourceAttrDiff) d := &ResourceData{ @@ -199,7 +199,7 @@ func (m schemaMap) Diff( // caused that. if result.RequiresNew() { // Create the new diff - result2 := new(terraform.ResourceDiff) + result2 := new(terraform.InstanceDiff) result2.Attributes = make(map[string]*terraform.ResourceAttrDiff) // Reset the data to not contain state @@ -344,7 +344,7 @@ func (m schemaMap) InternalValidate() error { func (m schemaMap) diff( k string, schema *Schema, - diff *terraform.ResourceDiff, + diff *terraform.InstanceDiff, d *ResourceData) error { var err error switch schema.Type { @@ -370,7 +370,7 @@ func (m schemaMap) diff( func (m schemaMap) diffList( k string, schema *Schema, - diff *terraform.ResourceDiff, + diff *terraform.InstanceDiff, d *ResourceData) error { o, n, _ := d.diffChange(k) @@ -465,7 +465,7 @@ func (m schemaMap) diffList( func (m schemaMap) diffMap( k string, schema *Schema, - diff *terraform.ResourceDiff, + diff *terraform.InstanceDiff, d *ResourceData) error { //elemSchema := &Schema{Type: TypeString} prefix := k + "." @@ -507,7 +507,7 @@ func (m schemaMap) diffMap( func (m schemaMap) diffSet( k string, schema *Schema, - diff *terraform.ResourceDiff, + diff *terraform.InstanceDiff, d *ResourceData) error { return m.diffList(k, schema, diff, d) } @@ -515,7 +515,7 @@ func (m schemaMap) diffSet( func (m schemaMap) diffString( k string, schema *Schema, - diff *terraform.ResourceDiff, + diff *terraform.InstanceDiff, d *ResourceData) error { var originalN interface{} var os, ns string diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 66e812055..91b958325 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -14,7 +14,7 @@ func TestSchemaMap_Diff(t *testing.T) { State *terraform.InstanceState Config map[string]interface{} ConfigVariables map[string]string - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Err bool }{ /* @@ -37,7 +37,7 @@ func TestSchemaMap_Diff(t *testing.T) { "availability_zone": "foo", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -64,7 +64,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: map[string]interface{}{}, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -112,7 +112,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -140,7 +140,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: nil, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -170,7 +170,7 @@ func TestSchemaMap_Diff(t *testing.T) { "availability_zone": "bar", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -201,7 +201,7 @@ func TestSchemaMap_Diff(t *testing.T) { "availability_zone": "foo", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -233,7 +233,7 @@ func TestSchemaMap_Diff(t *testing.T) { "var.foo": "bar", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -264,7 +264,7 @@ func TestSchemaMap_Diff(t *testing.T) { "var.foo": config.UnknownVariableValue, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", @@ -296,7 +296,7 @@ func TestSchemaMap_Diff(t *testing.T) { "port": 27, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", @@ -329,7 +329,7 @@ func TestSchemaMap_Diff(t *testing.T) { "port": false, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", @@ -361,7 +361,7 @@ func TestSchemaMap_Diff(t *testing.T) { "ports": []interface{}{1, 2, 5}, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", @@ -433,7 +433,7 @@ func TestSchemaMap_Diff(t *testing.T) { "ports": []interface{}{1, 2, 5}, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", @@ -465,7 +465,7 @@ func TestSchemaMap_Diff(t *testing.T) { "ports": []interface{}{1, 2, 5}, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", @@ -507,7 +507,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: map[string]interface{}{}, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "", @@ -541,7 +541,7 @@ func TestSchemaMap_Diff(t *testing.T) { "ports": []interface{}{5, 2, 1}, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", @@ -589,7 +589,7 @@ func TestSchemaMap_Diff(t *testing.T) { "ports": []interface{}{5, 2, 1}, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", @@ -627,7 +627,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: map[string]interface{}{}, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", @@ -703,7 +703,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "0", @@ -777,7 +777,7 @@ func TestSchemaMap_Diff(t *testing.T) { "port": 80, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ NewComputed: true, @@ -858,7 +858,7 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.0.foo": &terraform.ResourceAttrDiff{ Old: "bar", @@ -892,7 +892,7 @@ func TestSchemaMap_Diff(t *testing.T) { Config: map[string]interface{}{}, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "1", @@ -942,7 +942,7 @@ func TestSchemaMap_Diff(t *testing.T) { "availability_zone": "foo", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", @@ -991,7 +991,7 @@ func TestSchemaMap_Diff(t *testing.T) { "availability_zone": "foo", }, - Diff: &terraform.ResourceDiff{ + Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", diff --git a/rpc/resource_provider.go b/rpc/resource_provider.go index a3f8b243d..b9f106bc7 100644 --- a/rpc/resource_provider.go +++ b/rpc/resource_provider.go @@ -75,7 +75,7 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, - d *terraform.ResourceDiff) (*terraform.InstanceState, error) { + d *terraform.InstanceDiff) (*terraform.InstanceState, error) { var resp ResourceProviderApplyResponse args := &ResourceProviderApplyArgs{ Info: info, @@ -97,7 +97,7 @@ func (p *ResourceProvider) Apply( func (p *ResourceProvider) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { var resp ResourceProviderDiffResponse args := &ResourceProviderDiffArgs{ Info: info, @@ -158,9 +158,9 @@ type ResourceProviderConfigureResponse struct { } type ResourceProviderApplyArgs struct { - Info *terraform.InstanceInfo + Info *terraform.InstanceInfo State *terraform.InstanceState - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff } type ResourceProviderApplyResponse struct { @@ -169,19 +169,19 @@ type ResourceProviderApplyResponse struct { } type ResourceProviderDiffArgs struct { - Info *terraform.InstanceInfo + Info *terraform.InstanceInfo State *terraform.InstanceState Config *terraform.ResourceConfig } type ResourceProviderDiffResponse struct { - Diff *terraform.ResourceDiff + Diff *terraform.InstanceDiff Error *BasicError } type ResourceProviderRefreshArgs struct { - Info *terraform.InstanceInfo - State *terraform.InstanceState + Info *terraform.InstanceInfo + State *terraform.InstanceState } type ResourceProviderRefreshResponse struct { diff --git a/rpc/resource_provider_test.go b/rpc/resource_provider_test.go index e5c6a09f5..c8afffa05 100644 --- a/rpc/resource_provider_test.go +++ b/rpc/resource_provider_test.go @@ -108,7 +108,7 @@ func TestResourceProvider_apply(t *testing.T) { // Apply info := &terraform.InstanceInfo{} state := &terraform.InstanceState{} - diff := &terraform.ResourceDiff{} + diff := &terraform.InstanceDiff{} newState, err := provider.Apply(info, state, diff) if !p.ApplyCalled { t.Fatal("apply should be called") @@ -133,7 +133,7 @@ func TestResourceProvider_diff(t *testing.T) { } provider := &ResourceProvider{Client: client, Name: name} - p.DiffReturn = &terraform.ResourceDiff{ + p.DiffReturn = &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ Old: "", diff --git a/terraform/context.go b/terraform/context.go index f4fbd1fca..55b390fa4 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -746,7 +746,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { result.init() cb := func(r *Resource) error { - var diff *ResourceDiff + var diff *InstanceDiff for _, h := range c.hooks { handleHook(h.PreDiff(r.Id, r.State.Primary)) @@ -756,7 +756,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { log.Printf("[DEBUG] %s: Orphan, marking for destroy", r.Id) // This is an orphan (no config), so we mark it to be destroyed - diff = &ResourceDiff{Destroy: true} + diff = &InstanceDiff{Destroy: true} } else { // Make sure the configuration is interpolated if err := r.Config.interpolate(c); err != nil { @@ -781,7 +781,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { } if diff == nil { - diff = new(ResourceDiff) + diff = new(InstanceDiff) } if r.Tainted { @@ -858,7 +858,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { l.Lock() defer l.Unlock() - result.Diff.Resources[r.Id] = &ResourceDiff{Destroy: true} + result.Diff.Resources[r.Id] = &InstanceDiff{Destroy: true} } else { log.Printf("[DEBUG] %s: Not marking for destroy, no ID", r.Id) } diff --git a/terraform/context_test.go b/terraform/context_test.go index 6ef5706a1..44cb74532 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -411,8 +411,8 @@ func TestContextApply_badDiff(t *testing.T) { t.Fatalf("err: %s", err) } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "newp": nil, }, @@ -436,7 +436,7 @@ func TestContextApply_cancel(t *testing.T) { }, }) - p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { if !stopped { stopped = true go ctx.Stop() @@ -455,8 +455,8 @@ func TestContextApply_cancel(t *testing.T) { }, }, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ New: "bar", @@ -540,7 +540,7 @@ func TestContextApply_nilDiff(t *testing.T) { t.Fatalf("err: %s", err) } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { return nil, nil } @@ -709,7 +709,7 @@ func TestContextApply_outputDiffVars(t *testing.T) { State: s, }) - p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { for k, ad := range d.Attributes { if ad.NewComputed { return nil, fmt.Errorf("%s: computed", k) @@ -720,8 +720,8 @@ func TestContextApply_outputDiffVars(t *testing.T) { result.ID = "foo" return result, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ NewComputed: true, @@ -747,7 +747,7 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) { p := testProvider("aws") pr := testProvisioner() - p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { if s.Ephemeral.ConnInfo == nil { t.Fatalf("ConnInfo not initialized") } @@ -935,7 +935,7 @@ func TestContextApply_destroyOrphan(t *testing.T) { State: s, }) - p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { if d.Destroy { return nil, nil } @@ -944,8 +944,8 @@ func TestContextApply_destroyOrphan(t *testing.T) { result.ID = "foo" return result, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ New: "bar", @@ -981,7 +981,7 @@ func TestContextApply_error(t *testing.T) { }, }) - p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { if errored { state := &InstanceState{ ID: "bar", @@ -997,8 +997,8 @@ func TestContextApply_error(t *testing.T) { }, }, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ New: "bar", @@ -1051,7 +1051,7 @@ func TestContextApply_errorPartial(t *testing.T) { State: s, }) - p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { if errored { return s, fmt.Errorf("error") } @@ -1064,8 +1064,8 @@ func TestContextApply_errorPartial(t *testing.T) { }, }, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ New: "bar", @@ -1135,7 +1135,7 @@ func TestContextApply_idAttr(t *testing.T) { }, }) - p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) { + p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { result := s.MergeDiff(d) result.ID = "foo" result.Attributes = map[string]string{ @@ -1144,8 +1144,8 @@ func TestContextApply_idAttr(t *testing.T) { return result, nil } - p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) { - return &ResourceDiff{ + p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ New: "bar", @@ -1757,12 +1757,12 @@ func TestContextPlan_diffVar(t *testing.T) { p.DiffFn = func( info *InstanceInfo, s *InstanceState, - c *ResourceConfig) (*ResourceDiff, error) { + c *ResourceConfig) (*InstanceDiff, error) { if s.ID != "bar" { return testDiffFn(info, s, c) } - return &ResourceDiff{ + return &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "num": &ResourceAttrDiff{ Old: "2", @@ -2112,19 +2112,19 @@ func TestContextRefresh_hook(t *testing.T) { t.Fatal("should be called") } /* - TODO(mitchcellh): remove when we add InstanceInfo param - if h.PreRefreshState.Type != "aws_instance" { - t.Fatalf("bad: %#v", h.PreRefreshState) - } + TODO(mitchcellh): remove when we add InstanceInfo param + if h.PreRefreshState.Type != "aws_instance" { + t.Fatalf("bad: %#v", h.PreRefreshState) + } */ if !h.PostRefreshCalled { t.Fatal("should be called") } /* - TODO(mitchcellh): remove when we add InstanceInfo param - if h.PostRefreshState.Type != "aws_instance" { - t.Fatalf("bad: %#v", h.PostRefreshState) - } + TODO(mitchcellh): remove when we add InstanceInfo param + if h.PostRefreshState.Type != "aws_instance" { + t.Fatalf("bad: %#v", h.PostRefreshState) + } */ } @@ -2234,7 +2234,7 @@ func testContext(t *testing.T, opts *ContextOpts) *Context { func testApplyFn( info *InstanceInfo, s *InstanceState, - d *ResourceDiff) (*InstanceState, error) { + d *InstanceDiff) (*InstanceState, error) { if d.Destroy { return nil, nil } @@ -2266,8 +2266,8 @@ func testApplyFn( func testDiffFn( info *InstanceInfo, s *InstanceState, - c *ResourceConfig) (*ResourceDiff, error) { - var diff ResourceDiff + c *ResourceConfig) (*InstanceDiff, error) { + var diff InstanceDiff diff.Attributes = make(map[string]*ResourceAttrDiff) for k, v := range c.Raw { diff --git a/terraform/diff.go b/terraform/diff.go index b2b120685..64518f51f 100644 --- a/terraform/diff.go +++ b/terraform/diff.go @@ -18,7 +18,7 @@ const diffFormatByte byte = 1 // Diff tracks the differences between resources to apply. type Diff struct { - Resources map[string]*ResourceDiff + Resources map[string]*InstanceDiff once sync.Once } @@ -64,7 +64,7 @@ func WriteDiff(d *Diff, dst io.Writer) error { func (d *Diff) init() { d.once.Do(func() { if d.Resources == nil { - d.Resources = make(map[string]*ResourceDiff) + d.Resources = make(map[string]*InstanceDiff) } }) } @@ -152,8 +152,8 @@ func (d *Diff) String() string { return buf.String() } -// ResourceDiff is the diff of a resource from some state to another. -type ResourceDiff struct { +// InstanceDiff is the diff of a resource from some state to another. +type InstanceDiff struct { Attributes map[string]*ResourceAttrDiff Destroy bool @@ -188,7 +188,7 @@ const ( DiffAttrOutput ) -func (d *ResourceDiff) init() { +func (d *InstanceDiff) init() { d.once.Do(func() { if d.Attributes == nil { d.Attributes = make(map[string]*ResourceAttrDiff) @@ -197,7 +197,7 @@ func (d *ResourceDiff) init() { } // Empty returns true if this diff encapsulates no changes. -func (d *ResourceDiff) Empty() bool { +func (d *InstanceDiff) Empty() bool { if d == nil { return true } @@ -207,7 +207,7 @@ func (d *ResourceDiff) Empty() bool { // RequiresNew returns true if the diff requires the creation of a new // resource (implying the destruction of the old). -func (d *ResourceDiff) RequiresNew() bool { +func (d *InstanceDiff) RequiresNew() bool { if d == nil { return false } @@ -221,11 +221,11 @@ func (d *ResourceDiff) RequiresNew() bool { return false } -// Same checks whether or not to ResourceDiffs are the "same." When +// Same checks whether or not to InstanceDiff are the "same." When // we say "same", it is not necessarily exactly equal. Instead, it is // just checking that the same attributes are changing, a destroy // isn't suddenly happening, etc. -func (d *ResourceDiff) Same(d2 *ResourceDiff) bool { +func (d *InstanceDiff) Same(d2 *InstanceDiff) bool { if d == nil && d2 == nil { return true } else if d == nil || d2 == nil { diff --git a/terraform/diff_test.go b/terraform/diff_test.go index 12fc9c65b..5835dbff7 100644 --- a/terraform/diff_test.go +++ b/terraform/diff_test.go @@ -13,8 +13,8 @@ func TestDiff_Empty(t *testing.T) { t.Fatal("should be empty") } - diff.Resources = map[string]*ResourceDiff{ - "nodeA": &ResourceDiff{}, + diff.Resources = map[string]*InstanceDiff{ + "nodeA": &InstanceDiff{}, } if !diff.Empty() { @@ -42,8 +42,8 @@ func TestDiff_Empty(t *testing.T) { func TestDiff_String(t *testing.T) { diff := &Diff{ - Resources: map[string]*ResourceDiff{ - "nodeA": &ResourceDiff{ + Resources: map[string]*InstanceDiff{ + "nodeA": &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ Old: "foo", @@ -71,25 +71,25 @@ func TestDiff_String(t *testing.T) { } func TestResourceDiff_Empty(t *testing.T) { - var rd *ResourceDiff + var rd *InstanceDiff if !rd.Empty() { t.Fatal("should be empty") } - rd = new(ResourceDiff) + rd = new(InstanceDiff) if !rd.Empty() { t.Fatal("should be empty") } - rd = &ResourceDiff{Destroy: true} + rd = &InstanceDiff{Destroy: true} if rd.Empty() { t.Fatal("should not be empty") } - rd = &ResourceDiff{ + rd = &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ New: "bar", @@ -103,7 +103,7 @@ func TestResourceDiff_Empty(t *testing.T) { } func TestResourceDiff_RequiresNew(t *testing.T) { - rd := &ResourceDiff{ + rd := &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{}, }, @@ -121,7 +121,7 @@ func TestResourceDiff_RequiresNew(t *testing.T) { } func TestResourceDiff_RequiresNew_nil(t *testing.T) { - var rd *ResourceDiff + var rd *InstanceDiff if rd.RequiresNew() { t.Fatal("should not require new") @@ -130,12 +130,12 @@ func TestResourceDiff_RequiresNew_nil(t *testing.T) { func TestResourceDiffSame(t *testing.T) { cases := []struct { - One, Two *ResourceDiff + One, Two *InstanceDiff Same bool }{ { - &ResourceDiff{}, - &ResourceDiff{}, + &InstanceDiff{}, + &InstanceDiff{}, true, }, @@ -146,24 +146,24 @@ func TestResourceDiffSame(t *testing.T) { }, { - &ResourceDiff{Destroy: false}, - &ResourceDiff{Destroy: true}, + &InstanceDiff{Destroy: false}, + &InstanceDiff{Destroy: true}, false, }, { - &ResourceDiff{Destroy: true}, - &ResourceDiff{Destroy: true}, + &InstanceDiff{Destroy: true}, + &InstanceDiff{Destroy: true}, true, }, { - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{}, }, }, - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{}, }, @@ -172,12 +172,12 @@ func TestResourceDiffSame(t *testing.T) { }, { - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "bar": &ResourceAttrDiff{}, }, }, - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{}, }, @@ -186,12 +186,12 @@ func TestResourceDiffSame(t *testing.T) { }, { - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{RequiresNew: true}, }, }, - &ResourceDiff{ + &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{RequiresNew: false}, }, @@ -210,8 +210,8 @@ func TestResourceDiffSame(t *testing.T) { func TestReadWriteDiff(t *testing.T) { diff := &Diff{ - Resources: map[string]*ResourceDiff{ - "nodeA": &ResourceDiff{ + Resources: map[string]*InstanceDiff{ + "nodeA": &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ Old: "foo", diff --git a/terraform/graph.go b/terraform/graph.go index f5e7babd9..afeca1b7d 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -314,7 +314,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { *newNode.Resource = *rn.Resource // Make the diff _just_ the destroy. - newNode.Resource.Diff = &ResourceDiff{Destroy: true} + newNode.Resource.Diff = &InstanceDiff{Destroy: true} // Create the new node newN := &depgraph.Noun{ @@ -340,7 +340,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { // Mark the old diff to not destroy since we handle that in // the dedicated node. - newDiff := new(ResourceDiff) + newDiff := new(InstanceDiff) *newDiff = *rd newDiff.Destroy = false rd = newDiff diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 60bb14d89..15b15f637 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -251,8 +251,8 @@ func TestGraphProvisioners(t *testing.T) { func TestGraphAddDiff(t *testing.T) { config := testConfig(t, "graph-diff") diff := &Diff{ - Resources: map[string]*ResourceDiff{ - "aws_instance.foo": &ResourceDiff{ + Resources: map[string]*InstanceDiff{ + "aws_instance.foo": &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ New: "bar", @@ -287,11 +287,11 @@ func TestGraphAddDiff(t *testing.T) { func TestGraphAddDiff_destroy(t *testing.T) { config := testConfig(t, "graph-diff-destroy") diff := &Diff{ - Resources: map[string]*ResourceDiff{ - "aws_instance.foo": &ResourceDiff{ + Resources: map[string]*InstanceDiff{ + "aws_instance.foo": &InstanceDiff{ Destroy: true, }, - "aws_instance.bar": &ResourceDiff{ + "aws_instance.bar": &InstanceDiff{ Destroy: true, }, }, @@ -341,7 +341,7 @@ func TestGraphAddDiff_destroy(t *testing.T) { n := g.Noun("aws_instance.foo (destroy)") rn := n.Meta.(*GraphNodeResource) - expected2 := &ResourceDiff{Destroy: true} + expected2 := &InstanceDiff{Destroy: true} actual2 := rn.Resource.Diff if !reflect.DeepEqual(actual2, expected2) { t.Fatalf("bad: %#v", actual2) diff --git a/terraform/hook.go b/terraform/hook.go index fab4e7d65..430256fcc 100644 --- a/terraform/hook.go +++ b/terraform/hook.go @@ -24,13 +24,13 @@ type Hook interface { // PreApply and PostApply are called before and after a single // resource is applied. The error argument in PostApply is the // error, if any, that was returned from the provider Apply call itself. - PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) + PreApply(string, *InstanceState, *InstanceDiff) (HookAction, error) PostApply(string, *InstanceState, error) (HookAction, error) // PreDiff and PostDiff are called before and after a single resource // resource is diffed. PreDiff(string, *InstanceState) (HookAction, error) - PostDiff(string, *ResourceDiff) (HookAction, error) + PostDiff(string, *InstanceDiff) (HookAction, error) // Provisioning hooks PreProvisionResource(string, *InstanceState) (HookAction, error) @@ -49,7 +49,7 @@ type Hook interface { // and only implement the functions you are interested in. type NilHook struct{} -func (*NilHook) PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) { +func (*NilHook) PreApply(string, *InstanceState, *InstanceDiff) (HookAction, error) { return HookActionContinue, nil } @@ -61,7 +61,7 @@ func (*NilHook) PreDiff(string, *InstanceState) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostDiff(string, *ResourceDiff) (HookAction, error) { +func (*NilHook) PostDiff(string, *InstanceDiff) (HookAction, error) { return HookActionContinue, nil } diff --git a/terraform/hook_mock.go b/terraform/hook_mock.go index e991d495e..1ab053c41 100644 --- a/terraform/hook_mock.go +++ b/terraform/hook_mock.go @@ -5,7 +5,7 @@ package terraform type MockHook struct { PreApplyCalled bool PreApplyId string - PreApplyDiff *ResourceDiff + PreApplyDiff *InstanceDiff PreApplyState *InstanceState PreApplyReturn HookAction PreApplyError error @@ -25,7 +25,7 @@ type MockHook struct { PostDiffCalled bool PostDiffId string - PostDiffDiff *ResourceDiff + PostDiffDiff *InstanceDiff PostDiffReturn HookAction PostDiffError error @@ -66,7 +66,7 @@ type MockHook struct { PreRefreshError error } -func (h *MockHook) PreApply(n string, s *InstanceState, d *ResourceDiff) (HookAction, error) { +func (h *MockHook) PreApply(n string, s *InstanceState, d *InstanceDiff) (HookAction, error) { h.PreApplyCalled = true h.PreApplyId = n h.PreApplyDiff = d @@ -89,7 +89,7 @@ func (h *MockHook) PreDiff(n string, s *InstanceState) (HookAction, error) { return h.PreDiffReturn, h.PreDiffError } -func (h *MockHook) PostDiff(n string, d *ResourceDiff) (HookAction, error) { +func (h *MockHook) PostDiff(n string, d *InstanceDiff) (HookAction, error) { h.PostDiffCalled = true h.PostDiffId = n h.PostDiffDiff = d diff --git a/terraform/hook_stop.go b/terraform/hook_stop.go index 4beda674d..8c6c0f004 100644 --- a/terraform/hook_stop.go +++ b/terraform/hook_stop.go @@ -10,7 +10,7 @@ type stopHook struct { stop uint32 } -func (h *stopHook) PreApply(string, *InstanceState, *ResourceDiff) (HookAction, error) { +func (h *stopHook) PreApply(string, *InstanceState, *InstanceDiff) (HookAction, error) { return h.hook() } @@ -22,7 +22,7 @@ func (h *stopHook) PreDiff(string, *InstanceState) (HookAction, error) { return h.hook() } -func (h *stopHook) PostDiff(string, *ResourceDiff) (HookAction, error) { +func (h *stopHook) PostDiff(string, *InstanceDiff) (HookAction, error) { return h.hook() } diff --git a/terraform/plan_test.go b/terraform/plan_test.go index 7531186c3..985457260 100644 --- a/terraform/plan_test.go +++ b/terraform/plan_test.go @@ -11,8 +11,8 @@ func TestReadWritePlan(t *testing.T) { plan := &Plan{ Config: testConfig(t, "new-good"), Diff: &Diff{ - Resources: map[string]*ResourceDiff{ - "nodeA": &ResourceDiff{ + Resources: map[string]*InstanceDiff{ + "nodeA": &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ Old: "foo", diff --git a/terraform/resource.go b/terraform/resource.go index f912382be..18277db10 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -28,7 +28,7 @@ type ResourceProvisionerConfig struct { type Resource struct { Id string Config *ResourceConfig - Diff *ResourceDiff + Diff *InstanceDiff Provider ResourceProvider State *ResourceState Provisioners []*ResourceProvisionerConfig diff --git a/terraform/resource_provider.go b/terraform/resource_provider.go index 2bdf3c238..7a323f5af 100644 --- a/terraform/resource_provider.go +++ b/terraform/resource_provider.go @@ -48,14 +48,14 @@ type ResourceProvider interface { Apply( *InstanceInfo, *InstanceState, - *ResourceDiff) (*InstanceState, error) + *InstanceDiff) (*InstanceState, error) // Diff diffs a resource versus a desired state and returns // a diff. Diff( *InstanceInfo, *InstanceState, - *ResourceConfig) (*ResourceDiff, error) + *ResourceConfig) (*InstanceDiff, error) // Refresh refreshes a resource and updates all of its attributes // with the latest information. diff --git a/terraform/resource_provider_mock.go b/terraform/resource_provider_mock.go index 79c946dc2..d088594f8 100644 --- a/terraform/resource_provider_mock.go +++ b/terraform/resource_provider_mock.go @@ -15,8 +15,8 @@ type MockResourceProvider struct { ApplyCalled bool ApplyInfo *InstanceInfo ApplyState *InstanceState - ApplyDiff *ResourceDiff - ApplyFn func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) + ApplyDiff *InstanceDiff + ApplyFn func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) ApplyReturn *InstanceState ApplyReturnError error ConfigureCalled bool @@ -26,8 +26,8 @@ type MockResourceProvider struct { DiffInfo *InstanceInfo DiffState *InstanceState DiffDesired *ResourceConfig - DiffFn func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) - DiffReturn *ResourceDiff + DiffFn func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) + DiffReturn *InstanceDiff DiffReturnError error RefreshCalled bool RefreshInfo *InstanceInfo @@ -85,7 +85,7 @@ func (p *MockResourceProvider) Configure(c *ResourceConfig) error { func (p *MockResourceProvider) Apply( info *InstanceInfo, state *InstanceState, - diff *ResourceDiff) (*InstanceState, error) { + diff *InstanceDiff) (*InstanceState, error) { p.Lock() defer p.Unlock() @@ -103,7 +103,7 @@ func (p *MockResourceProvider) Apply( func (p *MockResourceProvider) Diff( info *InstanceInfo, state *InstanceState, - desired *ResourceConfig) (*ResourceDiff, error) { + desired *ResourceConfig) (*InstanceDiff, error) { p.Lock() defer p.Unlock() diff --git a/terraform/state.go b/terraform/state.go index fd5a7926f..d58d4cf5b 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -412,7 +412,7 @@ func (i *InstanceState) deepcopy() *InstanceState { // If the diff attribute requires computing the value, and hence // won't be available until apply, the value is replaced with the // computeID. -func (s *InstanceState) MergeDiff(d *ResourceDiff) *InstanceState { +func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { var result InstanceState if s != nil { result = *s diff --git a/terraform/state_test.go b/terraform/state_test.go index 13f953e3f..33cf4614f 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -21,7 +21,7 @@ func TestInstanceState_MergeDiff(t *testing.T) { }, } - diff := &ResourceDiff{ + diff := &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ Old: "bar", @@ -58,7 +58,7 @@ func TestInstanceState_MergeDiff(t *testing.T) { func TestInstanceState_MergeDiff_nil(t *testing.T) { var is *InstanceState = nil - diff := &ResourceDiff{ + diff := &InstanceDiff{ Attributes: map[string]*ResourceAttrDiff{ "foo": &ResourceAttrDiff{ Old: "", diff --git a/terraform/state_v1.go b/terraform/state_v1.go index fc0a90f5a..14436f205 100644 --- a/terraform/state_v1.go +++ b/terraform/state_v1.go @@ -226,7 +226,7 @@ type ResourceStateV1 struct { // If the diff attribute requires computing the value, and hence // won't be available until apply, the value is replaced with the // computeID. -func (s *ResourceStateV1) MergeDiff(d *ResourceDiff) *ResourceStateV1 { +func (s *ResourceStateV1) MergeDiff(d *InstanceDiff) *ResourceStateV1 { var result ResourceStateV1 if s != nil { result = *s diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 75fc36c60..d55050be4 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -60,7 +60,7 @@ type HookRecordApplyOrder struct { IDs []string States []*InstanceState - Diffs []*ResourceDiff + Diffs []*InstanceDiff l sync.Mutex } @@ -68,7 +68,7 @@ type HookRecordApplyOrder struct { func (h *HookRecordApplyOrder) PreApply( id string, s *InstanceState, - d *ResourceDiff) (HookAction, error) { + d *InstanceDiff) (HookAction, error) { if h.Active { h.l.Lock() defer h.l.Unlock() From e2aa067996aa20f2b4b674c5b891e2770cbc2576 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 16:47:26 -0700 Subject: [PATCH 39/85] terraform: fixing Refresh tests --- terraform/context.go | 2 +- terraform/context_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 55b390fa4..6635f8287 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -892,7 +892,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { // TODO: Handle other moduels mod := c.state.RootModule() - if len(r.State.Tainted) == 0 && (r.State.Primary == nil || r.State.Primary.ID == "") { + if len(r.State.Tainted) == 0 && (is == nil || is.ID == "") { delete(mod.Resources, r.Id) } else { mod.Resources[r.Id] = r.State diff --git a/terraform/context_test.go b/terraform/context_test.go index 44cb74532..8a64fda59 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2003,7 +2003,7 @@ func TestContextRefresh(t *testing.T) { if p.RefreshState.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) } From f9ce7de46897a8dba82cb71f7f5dd3923522daff Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 16:51:07 -0700 Subject: [PATCH 40/85] terraform: Refresh tests passing --- terraform/context.go | 5 ++--- terraform/context_test.go | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 6635f8287..fbc71bfe1 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -889,13 +889,12 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { } c.sl.Lock() - - // TODO: Handle other moduels + // TODO: Handle other modules mod := c.state.RootModule() if len(r.State.Tainted) == 0 && (is == nil || is.ID == "") { delete(mod.Resources, r.Id) } else { - mod.Resources[r.Id] = r.State + mod.Resources[r.Id].Primary = is } c.sl.Unlock() diff --git a/terraform/context_test.go b/terraform/context_test.go index 8a64fda59..7eda3899c 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2162,14 +2162,15 @@ func TestContextRefresh_state(t *testing.T) { if err != nil { t.Fatalf("err: %s", err) } + originalMod := state.RootModule() mod := s.RootModule() if !p.RefreshCalled { t.Fatal("refresh should be called") } - if !reflect.DeepEqual(p.RefreshState, mod.Resources["aws_instance.web"]) { + if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { t.Fatalf("bad: %#v", mod.Resources) } } @@ -2216,7 +2217,7 @@ func TestContextRefresh_vars(t *testing.T) { if p.RefreshState.ID != "foo" { t.Fatalf("bad: %#v", p.RefreshState) } - if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { + if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) } From bf072c586247524554795deb43483018d65c4a66 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 10:28:57 -0700 Subject: [PATCH 41/85] terraform: reorder list scan to reduce cost --- terraform/graph.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index afeca1b7d..e2bae00f8 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -327,6 +327,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { if _, ok := d.Target.Meta.(*GraphNodeResource); ok { continue } + // TODO: Maybe GraphNodeResourceMeta should be omitted? newN.Deps = append(newN.Deps, &depgraph.Dependency{ Name: d.Name, @@ -379,13 +380,13 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { // We have dependencies. We must be destroyed BEFORE those // dependencies. Look to see if they're managed. - for _, dep := range deps { - for _, n2 := range nlist { - // Don't ever depend on ourselves - if n2.Name == n.Name { - continue - } + for _, n2 := range nlist { + // Don't ever depend on ourselves + if n2.Name == n.Name { + continue + } + for _, dep := range deps { rn2 := n2.Meta.(*GraphNodeResource) if rn2.Resource.Id == dep { n2.Deps = append(n2.Deps, &depgraph.Dependency{ @@ -393,8 +394,6 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { Source: n2, Target: n, }) - - break } } } From 31653fcbcb3c86b2bfaef53fdc22adc8bf6c64e1 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 10:53:24 -0700 Subject: [PATCH 42/85] terraform: Adding utility methods --- terraform/util.go | 12 ++++++++++++ terraform/util_test.go | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 terraform/util.go create mode 100644 terraform/util_test.go diff --git a/terraform/util.go b/terraform/util.go new file mode 100644 index 000000000..f2654141f --- /dev/null +++ b/terraform/util.go @@ -0,0 +1,12 @@ +package terraform + +// strSliceContains checks if a given string is contained in a slice +// When anybody asks why Go needs generics, here you go. +func strSliceContains(haystack []string, needle string) bool { + for _, s := range haystack { + if s == needle { + return true + } + } + return false +} diff --git a/terraform/util_test.go b/terraform/util_test.go new file mode 100644 index 000000000..3b9818872 --- /dev/null +++ b/terraform/util_test.go @@ -0,0 +1,18 @@ +package terraform + +import "testing" + +func TestStrSliceContains(t *testing.T) { + if strSliceContains(nil, "foo") { + t.Fatalf("Bad") + } + if strSliceContains([]string{}, "foo") { + t.Fatalf("Bad") + } + if strSliceContains([]string{"bar"}, "foo") { + t.Fatalf("Bad") + } + if !strSliceContains([]string{"bar", "foo"}, "foo") { + t.Fatalf("Bad") + } +} From c14a17f39b431ef4d7d838f630691b27af1c6c59 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:01:45 -0700 Subject: [PATCH 43/85] terraform: save/restore dependency info for orphans --- terraform/context.go | 4 +++ terraform/graph.go | 80 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/terraform/context.go b/terraform/context.go index fbc71bfe1..ab719c17b 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -131,6 +131,10 @@ func (c *Context) Apply() (*State, error) { err = g.Walk(c.applyWalkFn()) log.Printf("[INFO] Apply walk complete") + // Encode the dependencies, this pushes the logical dependencies + // into the state so that we can recover it later. + EncodeDependencies(g) + // Prune the state so that we have as clean a state as possible c.state.prune() diff --git a/terraform/graph.go b/terraform/graph.go index e2bae00f8..fbdb75801 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -170,6 +170,45 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) { return g, nil } +// EncodeDependencies is used to walk the graph and encode the +// logical dependency information into the resource state. This +// allows the dependency tree to be recovered from the state file +// such that orphaned resources will still be destroyed in the +// proper order. +func EncodeDependencies(g *depgraph.Graph) { + for _, n := range g.Nouns { + // Ignore any non-resource nodes + rn, ok := n.Meta.(*GraphNodeResource) + if !ok { + continue + } + + // Skip only if the resource has state + rs := rn.Resource + state := rs.State + if state == nil { + continue + } + + // Update the dependencies + var inject []string + for _, dep := range n.Deps { + switch target := dep.Target.Meta.(type) { + case *GraphNodeResource: + inject = append(inject, target.Resource.Id) + // TODO: case *GraphNodeResourceMeta? + } + } + + // Inject any of the missing depedencies + for _, dep := range inject { + if !strSliceContains(state.Dependencies, dep) { + state.Dependencies = append(state.Dependencies, dep) + } + } + } +} + // configGraph turns a configuration structure into a dependency graph. func graphAddConfigResources( g *depgraph.Graph, c *config.Config, s *State) { @@ -513,6 +552,7 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { if mod == nil { return } + var nlist []*depgraph.Noun for _, k := range mod.Orphans(c) { rs := mod.Resources[k] noun := &depgraph.Noun{ @@ -528,7 +568,45 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { }, }, } - g.Nouns = append(g.Nouns, noun) + + // Append it to the list so we handle it later + nlist = append(nlist, noun) + } + + // Add the nouns to the graph + g.Nouns = append(g.Nouns, nlist...) + + // Handle the orphan dependencies after adding them + // to the graph because there may be depedencies between the + // orphans that otherwise cannot be handled + for _, n := range nlist { + rn := n.Meta.(*GraphNodeResource) + + // If we have no dependencies, then just continue + deps := rn.Resource.State.Dependencies + if len(deps) == 0 { + continue + } + + for _, n2 := range nlist { + rn2 := n2.Meta.(*GraphNodeResource) + // Don't ever depend on ourselves + if rn2 == rn { + continue + } + + for _, depName := range rn.Resource.State.Dependencies { + if rn2.Resource.Id != depName { + continue + } + dep := &depgraph.Dependency{ + Name: depName, + Source: n, + Target: n2, + } + n.Deps = append(n.Deps, dep) + } + } } } From 1aff5e98e1a186f9a966b06b4f801c1300b79c23 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 17:18:03 -0700 Subject: [PATCH 44/85] terraform: some deepcopying going on --- terraform/context.go | 20 +++++++++++++------- terraform/context_test.go | 2 +- terraform/state.go | 10 +++++----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index ab719c17b..ee965b3bf 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -752,8 +752,10 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { cb := func(r *Resource) error { var diff *InstanceDiff + is := r.State.Primary + for _, h := range c.hooks { - handleHook(h.PreDiff(r.Id, r.State.Primary)) + handleHook(h.PreDiff(r.Id, is)) } if r.Config == nil { @@ -794,15 +796,15 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { diff.Destroy = true } - if diff.RequiresNew() && r.State.Primary != nil && r.State.Primary.ID != "" { + if diff.RequiresNew() && is != nil && is.ID != "" { // This will also require a destroy diff.Destroy = true } - if diff.RequiresNew() || r.State.Primary == nil || r.State.Primary.ID == "" { + if diff.RequiresNew() || is == nil || is.ID == "" { var oldID string - if r.State.Primary != nil { - oldID = r.State.Primary.Attributes["id"] + if is != nil { + oldID = is.Attributes["id"] } // Add diff to compute new ID @@ -827,16 +829,20 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { // Determine the new state and update variables if !diff.Empty() { - r.State.Primary = r.State.Primary.MergeDiff(diff) + is = is.MergeDiff(diff) } + // TODO(mitchellh): do we really need this? + state := r.State.deepcopy() + state.Primary = is + // Update our internal state so that variable computation works c.sl.Lock() defer c.sl.Unlock() // TODO: Handle other modules mod := c.state.RootModule() - mod.Resources[r.Id] = r.State + mod.Resources[r.Id] = state return nil } diff --git a/terraform/context_test.go b/terraform/context_test.go index 7eda3899c..a31b0ec15 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1780,7 +1780,7 @@ func TestContextPlan_diffVar(t *testing.T) { actual := strings.TrimSpace(plan.String()) expected := strings.TrimSpace(testTerraformPlanDiffVarStr) if actual != expected { - t.Fatalf("bad:\n%s", actual) + t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) } } diff --git a/terraform/state.go b/terraform/state.go index d58d4cf5b..f0cec4c9e 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -413,11 +413,11 @@ func (i *InstanceState) deepcopy() *InstanceState { // won't be available until apply, the value is replaced with the // computeID. func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { - var result InstanceState - if s != nil { - result = *s + result := s.deepcopy() + if result == nil { + result = new(InstanceState) + result.init() } - result.init() if s != nil { for k, v := range s.Attributes { @@ -439,7 +439,7 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { } } - return &result + return result } func (i *InstanceState) GoString() string { From 9aa8bec6607834f9ae8058a3a46b986102b989d7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 17:23:19 -0700 Subject: [PATCH 45/85] terraform: update comments --- terraform/context.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/terraform/context.go b/terraform/context.go index ee965b3bf..40761da38 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -832,7 +832,13 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { is = is.MergeDiff(diff) } - // TODO(mitchellh): do we really need this? + // TODO(mitchellh): do we really need this? I had to do this because + // the pointer of r.State is shared with the original c.state + // which is now result.State, so modifying this was actually + // modifying the plan state, which is not what we want. I *think* + // this will be solved if we move to having InstanceState on + // type Resource rather than ResourceState, so I'm just going to + // keep this in here for now to get tests to work. state := r.State.deepcopy() state.Primary = is From cb8e581731322e698d916521e89379d3d6192271 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:29:02 -0700 Subject: [PATCH 46/85] terraform: test creates an actual logical dependence --- terraform/test-fixtures/apply-destroy/main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/terraform/test-fixtures/apply-destroy/main.tf b/terraform/test-fixtures/apply-destroy/main.tf index cd1a686f6..0ee93e5a8 100644 --- a/terraform/test-fixtures/apply-destroy/main.tf +++ b/terraform/test-fixtures/apply-destroy/main.tf @@ -5,6 +5,5 @@ resource "aws_instance" "foo" { resource "aws_instance" "bar" { id = "bar" - foo = "{aws_instance.foo.num}" - dep = "foo" + foo = "${aws_instance.foo.num}" } From af3c55096c528e006c46ff0c26b18a254b2a4920 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:29:54 -0700 Subject: [PATCH 47/85] terraform: handle logical dependencies during a delete --- terraform/graph.go | 84 ++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index fbdb75801..478111a74 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -360,20 +360,10 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { Name: fmt.Sprintf("%s (destroy)", newNode.Resource.Id), Meta: newNode, } - newN.Deps = make([]*depgraph.Dependency, 0, len(n.Deps)) - for _, d := range n.Deps { - // We don't want to copy any resource dependencies - if _, ok := d.Target.Meta.(*GraphNodeResource); ok { - continue - } - // TODO: Maybe GraphNodeResourceMeta should be omitted? + newN.Deps = make([]*depgraph.Dependency, len(n.Deps)) - newN.Deps = append(newN.Deps, &depgraph.Dependency{ - Name: d.Name, - Source: newN, - Target: d.Target, - }) - } + // Copy all the dependencies and do a fixup later + copy(newN.Deps, n.Deps) // Append it to the list so we handle it later nlist = append(nlist, newN) @@ -409,33 +399,53 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { // Go through each noun and make sure we calculate all the dependencies // properly. for _, n := range nlist { - rn := n.Meta.(*GraphNodeResource) - - // If we have no dependencies, then just continue - deps := rn.Resource.State.Dependencies - if len(deps) == 0 { - continue - } - - // We have dependencies. We must be destroyed BEFORE those - // dependencies. Look to see if they're managed. - for _, n2 := range nlist { - // Don't ever depend on ourselves - if n2.Name == n.Name { - continue - } - - for _, dep := range deps { - rn2 := n2.Meta.(*GraphNodeResource) - if rn2.Resource.Id == dep { - n2.Deps = append(n2.Deps, &depgraph.Dependency{ - Name: n.Name, - Source: n2, - Target: n, - }) + deps := n.Deps + num := len(deps) + for i := 0; i < num; i++ { + dep := deps[i] + switch target := dep.Target.Meta.(type) { + case *GraphNodeResource: + // If the other node is also being deleted, + // we must be deleted first. E.g. if A -> B, + // then when we create, B is created first then A. + // On teardown, A is destroyed first, then B. + // Thus we must flip our depedency and instead inject + // it on B. + for _, n2 := range nlist { + rn2 := n2.Meta.(*GraphNodeResource) + if target.Resource.Id == rn2.Resource.Id { + n2.Deps = append(n2.Deps, &depgraph.Dependency{ + Name: n.Name, + Source: n2, + Target: n, + }) + break + } } + + // Drop the dependency. We may have created + // an inverse depedency if the dependent resource + // is also being deleted, but this dependence is + // no longer required. + deps[i], deps[num-1] = deps[num-1], nil + num-- + i-- + + case *GraphNodeResourceMeta: + // Drop the dependency, since there is + // nothing that needs to be done for a meta + // resource on destroy. + deps[i], deps[num-1] = deps[num-1], nil + num-- + i-- + + case *GraphNodeResourceProvider: + // Keep these around + default: + panic(fmt.Errorf("Unhandled depedency type: %#v", dep.Meta)) } } + n.Deps = deps[:num] } // Add the nouns to the graph From dc01633f3c8098f68d889a9b5fc8e38a17087170 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:35:43 -0700 Subject: [PATCH 48/85] terraform: fixing outputs for destroy plan --- terraform/context.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 40761da38..2fac4d1a1 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -139,7 +139,8 @@ func (c *Context) Apply() (*State, error) { c.state.prune() // If we have no errors, then calculate the outputs if we have any - if err == nil && len(c.config.Outputs) > 0 { + root := c.state.RootModule() + if err == nil && len(c.config.Outputs) > 0 && len(root.Resources) > 0 { outputs := make(map[string]string) for _, o := range c.config.Outputs { if err = c.computeVars(o.RawConfig); err != nil { @@ -149,7 +150,7 @@ func (c *Context) Apply() (*State, error) { } // Assign the outputs to the root module - c.state.RootModule().Outputs = outputs + root.Outputs = outputs } return c.state, err From 9a0fe0171e5cf4eb53d9f06c93891372b7258095 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:40:59 -0700 Subject: [PATCH 49/85] terraform: fixing ContextApply_compute test --- terraform/terraform_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index d55050be4..58b67c404 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -106,6 +106,9 @@ aws_instance.bar: ID = foo foo = computed_dynamical type = aws_instance + + Dependencies: + aws_instance.foo aws_instance.foo: ID = foo dynamical = computed_dynamical From d4e2e66666629364d850ce2c18e72f138b6bba44 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:42:43 -0700 Subject: [PATCH 50/85] terraform: fixing provisioner tests --- terraform/terraform_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 58b67c404..8d5fb6d21 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -126,6 +126,9 @@ aws_instance.foo: const testTerraformApplyProvisionerStr = ` aws_instance.bar: ID = foo + + Dependencies: + aws_instance.foo aws_instance.foo: ID = foo dynamical = computed_dynamical From 17821f2b002c3b8eaf9b7006d8d91607110b23b2 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:45:38 -0700 Subject: [PATCH 51/85] terraform: fixing more test cases --- terraform/terraform_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 8d5fb6d21..5b0794a21 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -159,6 +159,9 @@ const testTerraformApplyDestroyStr = ` const testTerraformApplyErrorStr = ` aws_instance.bar: ID = bar + + Dependencies: + aws_instance.foo aws_instance.foo: ID = foo num = 2 @@ -167,6 +170,9 @@ aws_instance.foo: const testTerraformApplyErrorPartialStr = ` aws_instance.bar: ID = bar + + Dependencies: + aws_instance.foo aws_instance.foo: ID = foo num = 2 From 7a2591190b685c07aacc18433bfd86ec85259f93 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Sep 2014 17:52:24 -0700 Subject: [PATCH 52/85] terraform: fix graph test --- terraform/graph.go | 6 +++++- terraform/graph_test.go | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index 478111a74..c0954a2c3 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -440,7 +440,11 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { i-- case *GraphNodeResourceProvider: - // Keep these around + // Keep these around, but fix up the source to be ourselves + // rather than the old node. + newDep := *dep + newDep.Source = n + deps[i] = &newDep default: panic(fmt.Errorf("Unhandled depedency type: %#v", dep.Meta)) } diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 15b15f637..9d27b7cb6 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -334,7 +334,7 @@ func TestGraphAddDiff_destroy(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTerraformGraphDiffDestroyStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) } // Verify that the state has been added From 9c5f2c3061d6071364a58c1437349adcc26c6b2d Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 17:57:41 -0700 Subject: [PATCH 53/85] terraform: EncodeDependencies does not encode self dependence --- terraform/graph.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/terraform/graph.go b/terraform/graph.go index c0954a2c3..281053f29 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -195,6 +195,9 @@ func EncodeDependencies(g *depgraph.Graph) { for _, dep := range n.Deps { switch target := dep.Target.Meta.(type) { case *GraphNodeResource: + if target.Resource.Id == rs.Id { + continue + } inject = append(inject, target.Resource.Id) // TODO: case *GraphNodeResourceMeta? } From ed26e3d1693fe120619d34adbbcdae3da90b75ad Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 18:03:19 -0700 Subject: [PATCH 54/85] terraform: fixing test case string --- terraform/terraform_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 5b0794a21..6ac1781c1 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -494,7 +494,7 @@ aws_instance.foo: const testTerraformPlanTaintStr = ` DIFF: -DESTROY: aws_instance.bar +DESTROY/CREATE: aws_instance.bar foo: "" => "2" type: "" => "aws_instance" From 18a91a87c991a96b1c7566906003ebaac38a5116 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 18:13:38 -0700 Subject: [PATCH 55/85] terraform: first stab at read/write of state --- terraform/state.go | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index f0cec4c9e..cd9901c8a 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1,7 +1,9 @@ package terraform import ( + "bufio" "bytes" + "encoding/json" "fmt" "io" "reflect" @@ -476,12 +478,39 @@ func (e *EphemeralState) deepcopy() *EphemeralState { // ReadState reads a state structure out of a reader in the format that // was written by WriteState. func ReadState(src io.Reader) (*State, error) { - // TODO - return nil, nil + buf := bufio.NewReader(src) + + // Check if this is a V1 format + start, err := buf.Peek(len(stateFormatMagic)) + if err != nil { + return nil, fmt.Errorf("Failed to check for magic bytes: %v", err) + } + if string(start) == stateFormatMagic { + // Read the old state + _, err := ReadStateV1(buf) + if err != nil { + return nil, err + } + + // TODO: Handle V1 upgade + panic("Old state file upgrade not supported") + } + + // Otherwise, must be V2 + dec := json.NewDecoder(buf) + state := &State{} + if err := dec.Decode(state); err != nil { + return nil, fmt.Errorf("Decoding state file failed: %v", err) + } + + return state, nil } // WriteState writes a state somewhere in a binary format. func WriteState(d *State, dst io.Writer) error { - // TODO + enc := json.NewEncoder(dst) + if err := enc.Encode(d); err != nil { + return fmt.Errorf("Failed to write state: %v", err) + } return nil } From 4db7282072dba09bdffd234425d730ae55f4a388 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 17 Sep 2014 18:24:53 -0700 Subject: [PATCH 56/85] terraform: first pass at state file upgrades --- terraform/state.go | 49 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index cd9901c8a..73cb7edec 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "log" "reflect" "sort" @@ -487,13 +488,11 @@ func ReadState(src io.Reader) (*State, error) { } if string(start) == stateFormatMagic { // Read the old state - _, err := ReadStateV1(buf) + old, err := ReadStateV1(buf) if err != nil { return nil, err } - - // TODO: Handle V1 upgade - panic("Old state file upgrade not supported") + return upgradeV1State(old) } // Otherwise, must be V2 @@ -514,3 +513,45 @@ func WriteState(d *State, dst io.Writer) error { } return nil } + +// upgradeV1State is used to upgrade a V1 state representation +// into a proper State representation. +func upgradeV1State(old *StateV1) (*State, error) { + s := &State{} + s.init() + + // Old format had no modules, so we migrate everything + // directly into the root module. + root := s.RootModule() + + // Copy the outputs + root.Outputs = old.Outputs + + // Upgrade the resources + for id, rs := range old.Resources { + newRs := &ResourceState{ + Type: rs.Type, + } + root.Resources[id] = newRs + + // Migrate to an instance state + instance := &InstanceState{ + ID: rs.ID, + Attributes: rs.Attributes, + } + + // Check if this is the primary or tainted instance + if _, ok := old.Tainted[id]; ok { + newRs.Tainted = append(newRs.Tainted, instance) + } else { + newRs.Primary = instance + } + + // Warn if the resource uses Extra, as there is + // no upgrade path for this! Now totally deprecated. + if len(rs.Extra) > 0 { + log.Printf("[WARN] Resource %s uses deprecated attribute storage, state file upgrade may be incomplete.") + } + } + return s, nil +} From 1dcdd7a336f3e6b11de8024ec24941bd1bbad761 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 10:21:25 -0700 Subject: [PATCH 57/85] terraform: moving state v1 tests --- terraform/state_test.go | 103 ----------------------------------- terraform/state_v1_test.go | 109 +++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 103 deletions(-) create mode 100644 terraform/state_v1_test.go diff --git a/terraform/state_test.go b/terraform/state_test.go index 33cf4614f..02ecb2c8e 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -1,12 +1,7 @@ package terraform import ( - "bytes" - "encoding/gob" - "errors" - "io" "reflect" - "sync" "testing" "github.com/hashicorp/terraform/config" @@ -96,101 +91,3 @@ func TestInstanceState_MergeDiff_nilDiff(t *testing.T) { t.Fatalf("bad: %#v", is2.Attributes) } } - -func TestReadWriteStateV1(t *testing.T) { - state := &StateV1{ - Resources: map[string]*ResourceStateV1{ - "foo": &ResourceStateV1{ - ID: "bar", - ConnInfo: map[string]string{ - "type": "ssh", - "user": "root", - "password": "supersecret", - }, - }, - }, - } - - // Checksum before the write - chksum := checksumStruct(t, state) - - buf := new(bytes.Buffer) - if err := testWriteStateV1(state, buf); err != nil { - t.Fatalf("err: %s", err) - } - - // Checksum after the write - chksumAfter := checksumStruct(t, state) - if chksumAfter != chksum { - t.Fatalf("structure changed during serialization!") - } - - actual, err := ReadStateV1(buf) - if err != nil { - t.Fatalf("err: %s", err) - } - - // ReadState should not restore sensitive information! - state.Resources["foo"].ConnInfo = nil - - if !reflect.DeepEqual(actual, state) { - t.Fatalf("bad: %#v", actual) - } -} - -// sensitiveState is used to store sensitive state information -// that should not be serialized. This is only used temporarily -// and is restored into the state. -type sensitiveState struct { - ConnInfo map[string]map[string]string - - once sync.Once -} - -func (s *sensitiveState) init() { - s.once.Do(func() { - s.ConnInfo = make(map[string]map[string]string) - }) -} - -// testWriteStateV1 writes a state somewhere in a binary format. -// Only for testing now -func testWriteStateV1(d *StateV1, dst io.Writer) error { - // Write the magic bytes so we can determine the file format later - n, err := dst.Write([]byte(stateFormatMagic)) - if err != nil { - return err - } - if n != len(stateFormatMagic) { - return errors.New("failed to write state format magic bytes") - } - - // Write a version byte so we can iterate on version at some point - n, err = dst.Write([]byte{stateFormatVersion}) - if err != nil { - return err - } - if n != 1 { - return errors.New("failed to write state version byte") - } - - // Prevent sensitive information from being serialized - sensitive := &sensitiveState{} - sensitive.init() - for name, r := range d.Resources { - if r.ConnInfo != nil { - sensitive.ConnInfo[name] = r.ConnInfo - r.ConnInfo = nil - } - } - - // Serialize the state - err = gob.NewEncoder(dst).Encode(d) - - // Restore the state - for name, info := range sensitive.ConnInfo { - d.Resources[name].ConnInfo = info - } - - return err -} diff --git a/terraform/state_v1_test.go b/terraform/state_v1_test.go new file mode 100644 index 000000000..0e7bc3aa1 --- /dev/null +++ b/terraform/state_v1_test.go @@ -0,0 +1,109 @@ +package terraform + +import ( + "bytes" + "encoding/gob" + "errors" + "io" + "reflect" + "sync" + "testing" +) + +func TestReadWriteStateV1(t *testing.T) { + state := &StateV1{ + Resources: map[string]*ResourceStateV1{ + "foo": &ResourceStateV1{ + ID: "bar", + ConnInfo: map[string]string{ + "type": "ssh", + "user": "root", + "password": "supersecret", + }, + }, + }, + } + + // Checksum before the write + chksum := checksumStruct(t, state) + + buf := new(bytes.Buffer) + if err := testWriteStateV1(state, buf); err != nil { + t.Fatalf("err: %s", err) + } + + // Checksum after the write + chksumAfter := checksumStruct(t, state) + if chksumAfter != chksum { + t.Fatalf("structure changed during serialization!") + } + + actual, err := ReadStateV1(buf) + if err != nil { + t.Fatalf("err: %s", err) + } + + // ReadState should not restore sensitive information! + state.Resources["foo"].ConnInfo = nil + + if !reflect.DeepEqual(actual, state) { + t.Fatalf("bad: %#v", actual) + } +} + +// sensitiveState is used to store sensitive state information +// that should not be serialized. This is only used temporarily +// and is restored into the state. +type sensitiveState struct { + ConnInfo map[string]map[string]string + + once sync.Once +} + +func (s *sensitiveState) init() { + s.once.Do(func() { + s.ConnInfo = make(map[string]map[string]string) + }) +} + +// testWriteStateV1 writes a state somewhere in a binary format. +// Only for testing now +func testWriteStateV1(d *StateV1, dst io.Writer) error { + // Write the magic bytes so we can determine the file format later + n, err := dst.Write([]byte(stateFormatMagic)) + if err != nil { + return err + } + if n != len(stateFormatMagic) { + return errors.New("failed to write state format magic bytes") + } + + // Write a version byte so we can iterate on version at some point + n, err = dst.Write([]byte{stateFormatVersion}) + if err != nil { + return err + } + if n != 1 { + return errors.New("failed to write state version byte") + } + + // Prevent sensitive information from being serialized + sensitive := &sensitiveState{} + sensitive.init() + for name, r := range d.Resources { + if r.ConnInfo != nil { + sensitive.ConnInfo[name] = r.ConnInfo + r.ConnInfo = nil + } + } + + // Serialize the state + err = gob.NewEncoder(dst).Encode(d) + + // Restore the state + for name, info := range sensitive.ConnInfo { + d.Resources[name].ConnInfo = info + } + + return err +} From 15564b04a58ab1c21b45064dafc92e901ebe4df5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 18 Sep 2014 10:40:23 -0700 Subject: [PATCH 58/85] command: tests pass --- command/apply_test.go | 60 +++++++++++++++------------ command/plan_test.go | 91 +++++++++++++++++++---------------------- command/refresh_test.go | 26 ++++++++---- terraform/state.go | 31 ++++++++++++++ 4 files changed, 126 insertions(+), 82 deletions(-) diff --git a/command/apply_test.go b/command/apply_test.go index f6402ae44..21401ed47 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "reflect" + "strings" "sync" "testing" "time" @@ -580,13 +581,16 @@ func TestApply_state(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testApplyStateDiffStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } - if !reflect.DeepEqual(p.ApplyState, expectedState) { - t.Fatalf("bad: %#v", p.ApplyState) + actual = strings.TrimSpace(p.ApplyState.String()) + expected = strings.TrimSpace(testApplyStateStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } // Verify a new state exists @@ -866,22 +870,7 @@ func TestApply_backup(t *testing.T) { } func TestApply_disableBackup(t *testing.T) { - originalState := &terraform.State{ - Modules: []*terraform.ModuleState{ - &terraform.ModuleState{ - Path: []string{"root"}, - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - Type: "test_instance", - Primary: &terraform.InstanceState{ - ID: "bar", - }, - }, - }, - }, - }, - } - + originalState := testState() statePath := testStateFile(t, originalState) p := testProvider() @@ -912,13 +901,16 @@ func TestApply_disableBackup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testApplyDisableBackupStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } - if !reflect.DeepEqual(p.ApplyState, expectedState) { - t.Fatalf("bad: %#v", p.ApplyState) + actual = strings.TrimSpace(p.ApplyState.String()) + expected = strings.TrimSpace(testApplyDisableBackupStateStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } // Verify a new state exists @@ -950,3 +942,19 @@ func TestApply_disableBackup(t *testing.T) { const applyVarFile = ` foo = "bar" ` + +const testApplyDisableBackupStr = ` +ID = bar +` + +const testApplyDisableBackupStateStr = ` +ID = bar +` + +const testApplyStateStr = ` +ID = bar +` + +const testApplyStateDiffStr = ` +ID = bar +` diff --git a/command/plan_test.go b/command/plan_test.go index 2f9ec37e2..a22426f32 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "reflect" + "strings" "testing" "github.com/hashicorp/terraform/terraform" @@ -124,11 +125,10 @@ func TestPlan_noState(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := &terraform.ResourceState{ - Type: "test_instance", - } - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testPlanNoStateStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } } @@ -204,22 +204,7 @@ func TestPlan_state(t *testing.T) { statePath := tf.Name() defer os.Remove(tf.Name()) - originalState := &terraform.State{ - Modules: []*terraform.ModuleState{ - &terraform.ModuleState{ - Path: []string{"root"}, - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - Type: "test_instance", - Primary: &terraform.InstanceState{ - ID: "bar", - }, - }, - }, - }, - }, - } - + originalState := testState() err = terraform.WriteState(originalState, tf) tf.Close() if err != nil { @@ -244,28 +229,15 @@ func TestPlan_state(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testPlanStateStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } } func TestPlan_stateDefault(t *testing.T) { - originalState := &terraform.State{ - Modules: []*terraform.ModuleState{ - &terraform.ModuleState{ - Path: []string{"root"}, - Resources: map[string]*terraform.ResourceState{ - "test_instance.foo": &terraform.ResourceState{ - Type: "test_instance", - Primary: &terraform.InstanceState{ - ID: "bar", - }, - }, - }, - }, - }, - } + originalState := testState() // Write the state file in a temporary directory with the // default filename. @@ -312,9 +284,10 @@ func TestPlan_stateDefault(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testPlanStateDefaultStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } } @@ -502,9 +475,10 @@ func TestPlan_backup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testPlanBackupStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } // Verify the backup exist @@ -574,9 +548,10 @@ func TestPlan_disableBackup(t *testing.T) { } // Verify that the provider was called with the existing state - expectedState := originalState.RootModule().Resources["test_instance.foo"] - if !reflect.DeepEqual(p.DiffState, expectedState) { - t.Fatalf("bad: %#v", p.DiffState) + actual := strings.TrimSpace(p.DiffState.String()) + expected := strings.TrimSpace(testPlanDisableBackupStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } // Ensure there is no backup @@ -589,3 +564,23 @@ func TestPlan_disableBackup(t *testing.T) { const planVarFile = ` foo = "bar" ` + +const testPlanBackupStr = ` +ID = bar +` + +const testPlanDisableBackupStr = ` +ID = bar +` + +const testPlanNoStateStr = ` + +` + +const testPlanStateStr = ` +ID = bar +` + +const testPlanStateDefaultStr = ` +ID = bar +` diff --git a/command/refresh_test.go b/command/refresh_test.go index 073be20cd..b301fa022 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -6,6 +6,7 @@ import ( "path/filepath" "reflect" "testing" + "strings" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" @@ -50,10 +51,10 @@ func TestRefresh(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.RootModule().Resources["test_instance.foo"] - expected := p.RefreshReturn - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: %#v", actual) + actual := strings.TrimSpace(newState.String()) + expected := strings.TrimSpace(testRefreshStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } } @@ -123,10 +124,10 @@ func TestRefresh_cwd(t *testing.T) { t.Fatalf("err: %s", err) } - actual := newState.RootModule().Resources["test_instance.foo"] - expected := p.RefreshReturn - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: %#v", actual) + actual := strings.TrimSpace(newState.String()) + expected := strings.TrimSpace(testRefreshCwdStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) } } @@ -579,3 +580,12 @@ func TestRefresh_disableBackup(t *testing.T) { const refreshVarFile = ` foo = "bar" ` + +const testRefreshStr = ` +test_instance.foo: + ID = yes +` +const testRefreshCwdStr = ` +test_instance.foo: + ID = yes +` diff --git a/terraform/state.go b/terraform/state.go index 73cb7edec..a2f116651 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -449,6 +449,37 @@ func (i *InstanceState) GoString() string { return fmt.Sprintf("*%#v", *i) } +func (i *InstanceState) String() string { + var buf bytes.Buffer + + if i.ID == "" { + return "" + } + + buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID)) + if i.Tainted { + buf.WriteString(fmt.Sprintf("Tainted = true")) + } + + attributes := i.Attributes + attrKeys := make([]string, 0, len(attributes)) + for ak, _ := range attributes { + if ak == "id" { + continue + } + + attrKeys = append(attrKeys, ak) + } + sort.Strings(attrKeys) + + for _, ak := range attrKeys { + av := attributes[ak] + buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av)) + } + + return buf.String() +} + // EphemeralState is used for transient state that is only kept in-memory type EphemeralState struct { // ConnInfo is used for the providers to export information which is From 5adc55415b0eebf0a5ef96dc2816e286399a7621 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 10:51:39 -0700 Subject: [PATCH 59/85] terraform: testing new state file format --- terraform/state_test.go | 156 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/terraform/state_test.go b/terraform/state_test.go index 02ecb2c8e..5be330400 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -1,6 +1,7 @@ package terraform import ( + "bytes" "reflect" "testing" @@ -91,3 +92,158 @@ func TestInstanceState_MergeDiff_nilDiff(t *testing.T) { t.Fatalf("bad: %#v", is2.Attributes) } } + +func TestReadUpgradeState(t *testing.T) { + state := &StateV1{ + Resources: map[string]*ResourceStateV1{ + "foo": &ResourceStateV1{ + ID: "bar", + }, + }, + } + buf := new(bytes.Buffer) + if err := testWriteStateV1(state, buf); err != nil { + t.Fatalf("err: %s", err) + } + + // ReadState should transparently detect the old + // version and upgrade up so the latest. + actual, err := ReadState(buf) + if err != nil { + t.Fatalf("err: %s", err) + } + + upgraded, err := upgradeV1State(state) + if err != nil { + t.Fatalf("err: %s", err) + } + + if !reflect.DeepEqual(actual, upgraded) { + t.Fatalf("bad: %#v", actual) + } +} + +func TestReadWriteState(t *testing.T) { + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "foo": &ResourceState{ + Primary: &InstanceState{ + ID: "bar", + Ephemeral: EphemeralState{ + ConnInfo: map[string]string{ + "type": "ssh", + "user": "root", + "password": "supersecret", + }, + }, + }, + }, + }, + }, + }, + } + + // Checksum before the write + chksum := checksumStruct(t, state) + + buf := new(bytes.Buffer) + if err := WriteState(state, buf); err != nil { + t.Fatalf("err: %s", err) + } + + // Checksum after the write + chksumAfter := checksumStruct(t, state) + if chksumAfter != chksum { + t.Fatalf("structure changed during serialization!") + } + + actual, err := ReadState(buf) + if err != nil { + t.Fatalf("err: %s", err) + } + + // ReadState should not restore sensitive information! + mod := state.RootModule() + mod.Resources["foo"].Primary.Ephemeral = EphemeralState{} + + if !reflect.DeepEqual(actual, state) { + t.Fatalf("bad: %#v", actual) + } +} + +func TestUpgradeV1State(t *testing.T) { + old := &StateV1{ + Outputs: map[string]string{ + "ip": "127.0.0.1", + }, + Resources: map[string]*ResourceStateV1{ + "foo": &ResourceStateV1{ + Type: "test_resource", + ID: "bar", + Attributes: map[string]string{ + "key": "val", + }, + }, + "bar": &ResourceStateV1{ + Type: "test_resource", + ID: "1234", + Attributes: map[string]string{ + "a": "b", + }, + }, + }, + Tainted: map[string]struct{}{ + "bar": struct{}{}, + }, + } + state, err := upgradeV1State(old) + if err != nil { + t.Fatalf("err: %v", err) + } + + if len(state.Modules) != 1 { + t.Fatalf("should only have root module: %#v", state.Modules) + } + root := state.RootModule() + + if len(root.Outputs) != 1 { + t.Fatalf("bad outputs: %v", root.Outputs) + } + if root.Outputs["ip"] != "127.0.0.1" { + t.Fatalf("bad outputs: %v", root.Outputs) + } + + if len(root.Resources) != 2 { + t.Fatalf("bad resources: %v", root.Resources) + } + + foo := root.Resources["foo"] + if foo.Type != "test_resource" { + t.Fatalf("bad: %#v", foo) + } + if foo.Primary == nil || foo.Primary.ID != "bar" || + foo.Primary.Attributes["key"] != "val" { + t.Fatalf("bad: %#v", foo) + } + if len(foo.Tainted) > 0 { + t.Fatalf("bad: %#v", foo) + } + + bar := root.Resources["bar"] + if bar.Type != "test_resource" { + t.Fatalf("bad: %#v", bar) + } + if bar.Primary != nil { + t.Fatalf("bad: %#v", bar) + } + if len(bar.Tainted) != 1 { + t.Fatalf("bad: %#v", bar) + } + bt := bar.Tainted[0] + if bt.ID != "1234" || bt.Attributes["a"] != "b" { + t.Fatalf("bad: %#v", bt) + } +} From 364d210e59122b60db27cec8cc0089e9e5c7691a Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 11:02:14 -0700 Subject: [PATCH 60/85] terraform: fixing destroy dependency flipping twice --- terraform/graph.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index 281053f29..b795f4ceb 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -401,11 +401,19 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { // Go through each noun and make sure we calculate all the dependencies // properly. + injected := make(map[*depgraph.Dependency]struct{}) for _, n := range nlist { deps := n.Deps num := len(deps) for i := 0; i < num; i++ { dep := deps[i] + + // Check if this dependency was just injected, otherwise + // we will incorrectly flip the depedency twice. + if _, ok := injected[dep]; ok { + continue + } + switch target := dep.Target.Meta.(type) { case *GraphNodeResource: // If the other node is also being deleted, @@ -417,11 +425,13 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { for _, n2 := range nlist { rn2 := n2.Meta.(*GraphNodeResource) if target.Resource.Id == rn2.Resource.Id { - n2.Deps = append(n2.Deps, &depgraph.Dependency{ + newDep := &depgraph.Dependency{ Name: n.Name, Source: n2, Target: n, - }) + } + injected[newDep] = struct{}{} + n2.Deps = append(n2.Deps, newDep) break } } From d61f199d6fc600fd8b4dd8a155a9512260b7ec69 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 11:12:39 -0700 Subject: [PATCH 61/85] terraform: test dependency encoding --- terraform/graph_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 9d27b7cb6..0623c347a 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -354,6 +354,50 @@ func TestGraphAddDiff_destroy(t *testing.T) { } } +func TestEncodeDependencies(t *testing.T) { + config := testConfig(t, "graph-basic") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_load_balancer.weblb": &ResourceState{ + Type: "aws_load_balancer", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, + }, + }, + } + + g, err := Graph(&GraphOpts{Config: config, State: state}) + if err != nil { + t.Fatalf("err: %s", err) + } + + // This should encode the dependency information into the state + EncodeDependencies(g) + + root := state.RootModule() + web := root.Resources["aws_instance.web"] + if len(web.Dependencies) != 1 || web.Dependencies[0] != "aws_security_group.firewall" { + t.Fatalf("bad: %#v", web) + } + + weblb := root.Resources["aws_load_balancer.weblb"] + if len(weblb.Dependencies) != 1 || weblb.Dependencies[0] != "aws_instance.web" { + t.Fatalf("bad: %#v", weblb) + } +} + const testTerraformGraphStr = ` root: root aws_instance.web From a9c4b523db41b0cecee12dd296f0aee181e00823 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 11:22:40 -0700 Subject: [PATCH 62/85] terraform: Encode dependencies of ResourceMeta ndoes --- terraform/graph.go | 8 +++++++- terraform/graph_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/terraform/graph.go b/terraform/graph.go index b795f4ceb..303a638f4 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -199,7 +199,13 @@ func EncodeDependencies(g *depgraph.Graph) { continue } inject = append(inject, target.Resource.Id) - // TODO: case *GraphNodeResourceMeta? + + case *GraphNodeResourceMeta: + // Inject each sub-resource as a depedency + for i := 0; i < target.Count; i++ { + id := fmt.Sprintf("%s.%d", target.ID, i) + inject = append(inject, id) + } } } diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 0623c347a..fbf444759 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -398,6 +398,50 @@ func TestEncodeDependencies(t *testing.T) { } } +func TestEncodeDependencies_Count(t *testing.T) { + config := testConfig(t, "graph-count") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_load_balancer.weblb": &ResourceState{ + Type: "aws_load_balancer", + Primary: &InstanceState{ + ID: "foo", + }, + }, + }, + }, + }, + } + + g, err := Graph(&GraphOpts{Config: config, State: state}) + if err != nil { + t.Fatalf("err: %s", err) + } + + // This should encode the dependency information into the state + EncodeDependencies(g) + + root := state.RootModule() + web := root.Resources["aws_instance.web.0"] + if len(web.Dependencies) != 0 { + t.Fatalf("bad: %#v", web) + } + + weblb := root.Resources["aws_load_balancer.weblb"] + if len(weblb.Dependencies) != 3 { + t.Fatalf("bad: %#v", weblb) + } +} + const testTerraformGraphStr = ` root: root aws_instance.web From 3b7c987889172cca4a943e9ed14472a5e154f9d4 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 13:33:05 -0700 Subject: [PATCH 63/85] terraform: EncodeDepedencies should override dep list --- terraform/context_test.go | 9 --------- terraform/graph.go | 8 ++------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/terraform/context_test.go b/terraform/context_test.go index a31b0ec15..780815bbb 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2252,15 +2252,6 @@ func testApplyFn( if d != nil { result = result.MergeDiff(d) } - - // TODO(armon): commenting this out to compile, but you're in the - // process of removing this, too anyways. Remove when safe. - /* - if depAttr, ok := d.Attributes["dep"]; ok { - result.Dependencies = []string{depAttr.New} - } - */ - return result, nil } diff --git a/terraform/graph.go b/terraform/graph.go index 303a638f4..65fcef650 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -209,12 +209,8 @@ func EncodeDependencies(g *depgraph.Graph) { } } - // Inject any of the missing depedencies - for _, dep := range inject { - if !strSliceContains(state.Dependencies, dep) { - state.Dependencies = append(state.Dependencies, dep) - } - } + // Update the dependencies + state.Dependencies = inject } } From ec4be66f635ba34abe8be4668f5424f0bb3359ae Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 13:38:36 -0700 Subject: [PATCH 64/85] terraform: ensure file version is set and serial incremented --- terraform/state.go | 6 ++++++ terraform/state_test.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index a2f116651..640f6d353 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -538,6 +538,12 @@ func ReadState(src io.Reader) (*State, error) { // WriteState writes a state somewhere in a binary format. func WriteState(d *State, dst io.Writer) error { + // Ensure the version is set + d.Version = textStateVersion + + // Always increment the serial number + d.Serial++ + enc := json.NewEncoder(dst) if err := enc.Encode(d); err != nil { return fmt.Errorf("Failed to write state: %v", err) diff --git a/terraform/state_test.go b/terraform/state_test.go index 5be330400..097abde91 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -125,6 +125,7 @@ func TestReadUpgradeState(t *testing.T) { func TestReadWriteState(t *testing.T) { state := &State{ + Serial: 9, Modules: []*ModuleState{ &ModuleState{ Path: rootModulePath, @@ -154,6 +155,20 @@ func TestReadWriteState(t *testing.T) { t.Fatalf("err: %s", err) } + // Verify that the version and serial are set + if state.Version != textStateVersion { + t.Fatalf("bad version number: %d", state.Version) + } + + // Verify the serial number is incremented + if state.Serial != 10 { + t.Fatalf("bad serial: %d", state.Serial) + } + + // Remove the changes or the checksum will fail + state.Version = 0 + state.Serial = 9 + // Checksum after the write chksumAfter := checksumStruct(t, state) if chksumAfter != chksum { @@ -165,6 +180,10 @@ func TestReadWriteState(t *testing.T) { t.Fatalf("err: %s", err) } + // Verify the changes came through + state.Version = textStateVersion + state.Serial = 10 + // ReadState should not restore sensitive information! mod := state.RootModule() mod.Resources["foo"].Primary.Ephemeral = EphemeralState{} From 68614aeb79f6d90b9a9e8a1ea200ac2c72612476 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 13:43:26 -0700 Subject: [PATCH 65/85] terraform: Guard against future version changes --- terraform/state.go | 6 ++++++ terraform/state_test.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index 640f6d353..37845072f 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -533,6 +533,12 @@ func ReadState(src io.Reader) (*State, error) { return nil, fmt.Errorf("Decoding state file failed: %v", err) } + // Check the version, this to ensure we don't read a future + // version that we don't understand + if state.Version > textStateVersion { + return nil, fmt.Errorf("State version %d not supported, please update.", + state.Version) + } return state, nil } diff --git a/terraform/state_test.go b/terraform/state_test.go index 097abde91..3066f0b7d 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -2,7 +2,9 @@ package terraform import ( "bytes" + "encoding/json" "reflect" + "strings" "testing" "github.com/hashicorp/terraform/config" @@ -193,6 +195,25 @@ func TestReadWriteState(t *testing.T) { } } +func TestReadStateNewVersion(t *testing.T) { + type out struct { + Version int + } + + buf, err := json.Marshal(&out{textStateVersion + 1}) + if err != nil { + t.Fatalf("err: %v", err) + } + + s, err := ReadState(bytes.NewReader(buf)) + if s != nil { + t.Fatalf("unexpected: %#v", s) + } + if !strings.Contains(err.Error(), "not supported") { + t.Fatalf("err: %v", err) + } +} + func TestUpgradeV1State(t *testing.T) { old := &StateV1{ Outputs: map[string]string{ From b2188d7fe8de7322136529c07125146167257c44 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 14:31:27 -0700 Subject: [PATCH 66/85] terraform: properly handle diff generation with meta resources --- terraform/graph.go | 19 +++++++ terraform/graph_test.go | 114 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/terraform/graph.go b/terraform/graph.go index 65fcef650..303a6e659 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -447,6 +447,25 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { i-- case *GraphNodeResourceMeta: + // Check if any of the resources part of the meta node + // are being destroyed, because we must be destroyed first. + for i := 0; i < target.Count; i++ { + id := fmt.Sprintf("%s.%d", target.ID, i) + for _, n2 := range nlist { + rn2 := n2.Meta.(*GraphNodeResource) + if id == rn2.Resource.Id { + newDep := &depgraph.Dependency{ + Name: n.Name, + Source: n2, + Target: n, + } + injected[newDep] = struct{}{} + n2.Deps = append(n2.Deps, newDep) + break + } + } + } + // Drop the dependency, since there is // nothing that needs to be done for a meta // resource on destroy. diff --git a/terraform/graph_test.go b/terraform/graph_test.go index fbf444759..3f64380df 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -354,6 +354,93 @@ func TestGraphAddDiff_destroy(t *testing.T) { } } +func TestGraphAddDiff_destroy_counts(t *testing.T) { + config := testConfig(t, "graph-count") + diff := &Diff{ + Resources: map[string]*InstanceDiff{ + "aws_instance.web.0": &InstanceDiff{ + Destroy: true, + }, + "aws_instance.web.1": &InstanceDiff{ + Destroy: true, + }, + "aws_instance.web.2": &InstanceDiff{ + Destroy: true, + }, + "aws_load_balancer.weblb": &InstanceDiff{ + Destroy: true, + }, + }, + } + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_instance.web.1": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_instance.web.2": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_load_balancer.weblb": &ResourceState{ + Type: "aws_load_balancer", + Dependencies: []string{"aws_instance.web.0", "aws_instance.web.1", "aws_instance.web.2"}, + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } + + diffHash := checksumStruct(t, diff) + + g, err := Graph(&GraphOpts{ + Config: config, + Diff: diff, + State: state, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTerraformGraphDiffDestroyCountsStr) + if actual != expected { + t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) + } + + // Verify that the state has been added + n := g.Noun("aws_instance.web.0 (destroy)") + rn := n.Meta.(*GraphNodeResource) + + expected2 := &InstanceDiff{Destroy: true} + actual2 := rn.Resource.Diff + if !reflect.DeepEqual(actual2, expected2) { + t.Fatalf("bad: %#v", actual2) + } + + // Verify that our original structure has not been modified + diffHash2 := checksumStruct(t, diff) + if diffHash != diffHash2 { + t.Fatal("diff has been modified") + } +} + func TestEncodeDependencies(t *testing.T) { config := testConfig(t, "graph-basic") state := &State{ @@ -530,6 +617,33 @@ root root -> aws_instance.foo ` +const testTerraformGraphDiffDestroyCountsStr = ` +root: root +aws_instance.web + aws_instance.web -> aws_instance.web.0 + aws_instance.web -> aws_instance.web.1 + aws_instance.web -> aws_instance.web.2 +aws_instance.web.0 + aws_instance.web.0 -> aws_instance.web.0 (destroy) +aws_instance.web.0 (destroy) + aws_instance.web.0 (destroy) -> aws_load_balancer.weblb (destroy) +aws_instance.web.1 + aws_instance.web.1 -> aws_instance.web.1 (destroy) +aws_instance.web.1 (destroy) + aws_instance.web.1 (destroy) -> aws_load_balancer.weblb (destroy) +aws_instance.web.2 + aws_instance.web.2 -> aws_instance.web.2 (destroy) +aws_instance.web.2 (destroy) + aws_instance.web.2 (destroy) -> aws_load_balancer.weblb (destroy) +aws_load_balancer.weblb + aws_load_balancer.weblb -> aws_instance.web + aws_load_balancer.weblb -> aws_load_balancer.weblb (destroy) +aws_load_balancer.weblb (destroy) +root + root -> aws_instance.web + root -> aws_load_balancer.weblb +` + const testTerraformGraphStateStr = ` root: root aws_instance.old From 5ef46b797b3b98acd8d9a8be50113c518cfe07e6 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 15:39:53 -0700 Subject: [PATCH 67/85] terraform: fixing dependency handling for orphans --- terraform/graph.go | 8 +++-- terraform/graph_test.go | 69 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index 303a6e659..b833d5a00 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -636,8 +636,12 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { continue } - for _, n2 := range nlist { - rn2 := n2.Meta.(*GraphNodeResource) + for _, n2 := range g.Nouns { + rn2, ok := n2.Meta.(*GraphNodeResource) + if !ok { + continue + } + // Don't ever depend on ourselves if rn2 == rn { continue diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 3f64380df..69adb5a00 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -529,6 +529,54 @@ func TestEncodeDependencies_Count(t *testing.T) { } } +func TestGraph_orphan_dependencies(t *testing.T) { + config := testConfig(t, "graph-count") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + + Resources: map[string]*ResourceState{ + "aws_instance.web.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_instance.web.1": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_load_balancer.old": &ResourceState{ + Type: "aws_load_balancer", + Primary: &InstanceState{ + ID: "foo", + }, + Dependencies: []string{ + "aws_instance.web.0", + "aws_instance.web.1", + "aws_instance.web.2", + }, + }, + }, + }, + }, + } + + g, err := Graph(&GraphOpts{Config: config, State: state}) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTerraformGraphCountOrphanStr) + if actual != expected { + t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) + } +} + const testTerraformGraphStr = ` root: root aws_instance.web @@ -666,3 +714,24 @@ root root -> aws_security_group.firewall root -> openstack_floating_ip.random ` + +const testTerraformGraphCountOrphanStr = ` +root: root +aws_instance.web + aws_instance.web -> aws_instance.web.0 + aws_instance.web -> aws_instance.web.1 + aws_instance.web -> aws_instance.web.2 +aws_instance.web.0 +aws_instance.web.1 +aws_instance.web.2 +aws_load_balancer.old + aws_load_balancer.old -> aws_instance.web.0 + aws_load_balancer.old -> aws_instance.web.1 + aws_load_balancer.old -> aws_instance.web.2 +aws_load_balancer.weblb + aws_load_balancer.weblb -> aws_instance.web +root + root -> aws_instance.web + root -> aws_load_balancer.old + root -> aws_load_balancer.weblb +` From 91eb3c73fcb24a48c0250b6bf6c2a2a75a886ec4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 18 Sep 2014 18:16:09 -0600 Subject: [PATCH 68/85] command: fix failing tests --- command/apply_test.go | 12 ++++++++---- command/plan_test.go | 14 +++++++++----- command/refresh_test.go | 12 ++++++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/command/apply_test.go b/command/apply_test.go index 21401ed47..972371331 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -438,8 +438,10 @@ func TestApply_refresh(t *testing.T) { t.Fatalf("err: %s", err) } - if !reflect.DeepEqual(backupState, originalState) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(originalState.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } @@ -627,8 +629,10 @@ func TestApply_state(t *testing.T) { // nil out the ConnInfo since that should not be restored originalState.RootModule().Resources["test_instance.foo"].Primary.Ephemeral.ConnInfo = nil - if !reflect.DeepEqual(backupState, originalState) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(originalState.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } diff --git a/command/plan_test.go b/command/plan_test.go index a22426f32..76049f491 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "strings" "testing" @@ -98,10 +97,13 @@ func TestPlan_destroy(t *testing.T) { t.Fatalf("err: %s", err) } - if !reflect.DeepEqual(backupState, originalState) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(originalState.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } + func TestPlan_noState(t *testing.T) { p := testProvider() ui := new(cli.MockUi) @@ -493,8 +495,10 @@ func TestPlan_backup(t *testing.T) { t.Fatalf("err: %s", err) } - if !reflect.DeepEqual(backupState, originalState) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(originalState.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } diff --git a/command/refresh_test.go b/command/refresh_test.go index b301fa022..1281f4c18 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -297,8 +297,10 @@ func TestRefresh_outPath(t *testing.T) { t.Fatalf("err: %s", err) } - if !reflect.DeepEqual(backupState, state) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(state.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } @@ -498,8 +500,10 @@ func TestRefresh_backup(t *testing.T) { t.Fatalf("err: %s", err) } - if !reflect.DeepEqual(backupState, state) { - t.Fatalf("bad: %#v", backupState) + actualStr := strings.TrimSpace(backupState.String()) + expectedStr := strings.TrimSpace(state.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr) } } From a1c4a2771593900643641dd5201ee0e7ab168f18 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 17:29:21 -0700 Subject: [PATCH 69/85] terraform: Drop useless field --- terraform/state.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index 37845072f..5c33012d9 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -368,11 +368,6 @@ type InstanceState struct { // and is only meant as a lookup mechanism for the providers. ID string `json:"id"` - // Tainted is used to mark a resource as existing but being in - // an unknown or errored state. Hence, it is 'tainted' and should - // be destroyed and replaced on the next fun. - Tainted bool `json:"tainted,omitempty"` - // Attributes are basic information about the resource. Any keys here // are accessible in variable format within Terraform configurations: // ${resourcetype.name.attribute}. @@ -397,7 +392,6 @@ func (i *InstanceState) deepcopy() *InstanceState { } n := &InstanceState{ ID: i.ID, - Tainted: i.Tainted, Attributes: make(map[string]string, len(i.Attributes)), Ephemeral: *i.Ephemeral.deepcopy(), } @@ -457,9 +451,6 @@ func (i *InstanceState) String() string { } buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID)) - if i.Tainted { - buf.WriteString(fmt.Sprintf("Tainted = true")) - } attributes := i.Attributes attrKeys := make([]string, 0, len(attributes)) From 9594ed6e1cc1244f06a8b05f86a576353b042c74 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 19 Sep 2014 14:54:21 -0700 Subject: [PATCH 70/85] terraform: minor cleanup --- terraform/graph.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/terraform/graph.go b/terraform/graph.go index b833d5a00..b8c16c9e5 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -217,6 +217,9 @@ func EncodeDependencies(g *depgraph.Graph) { // configGraph turns a configuration structure into a dependency graph. func graphAddConfigResources( g *depgraph.Graph, c *config.Config, s *State) { + // TODO: Handle non-root modules + mod := s.ModuleByPath(rootModulePath) + // This tracks all the resource nouns nouns := make(map[string]*depgraph.Noun) for _, r := range c.Resources { @@ -232,12 +235,7 @@ func graphAddConfigResources( index = i } - tainted := false var state *ResourceState - - // TODO: Handle non-root modules - mod := s.ModuleByPath(rootModulePath) - if s != nil && mod != nil { // Lookup the resource state state = mod.Resources[name] @@ -254,11 +252,6 @@ func graphAddConfigResources( state = mod.Resources[r.Id()] } } - - // Determine if this resource is tainted - if state != nil && len(state.Tainted) > 0 { - tainted = true - } } if state == nil { @@ -277,7 +270,7 @@ func graphAddConfigResources( Id: name, State: state, Config: NewResourceConfig(r.RawConfig), - Tainted: tainted, + Tainted: len(state.Tainted) > 0, }, }, } From ff42a9263628fe9c20dd3d389157de5f8bd7ae8d Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 19 Sep 2014 14:55:59 -0700 Subject: [PATCH 71/85] terraform: State string includes how many resources are tainted --- terraform/state.go | 2 +- terraform/terraform_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index 5c33012d9..7122d3763 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -134,7 +134,7 @@ func (s *State) String() string { taintStr := "" if len(rs.Tainted) > 0 { - taintStr = " (tainted)" + taintStr = fmt.Sprintf(" (%d tainted)", len(rs.Tainted)) } buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 6ac1781c1..e86c3f5e1 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -137,7 +137,7 @@ aws_instance.foo: ` const testTerraformApplyProvisionerFailStr = ` -aws_instance.bar: (tainted) +aws_instance.bar: (1 tainted) ID = foo aws_instance.foo: ID = foo @@ -500,7 +500,7 @@ DESTROY/CREATE: aws_instance.bar STATE: -aws_instance.bar: (tainted) +aws_instance.bar: (1 tainted) ID = baz aws_instance.foo: ID = bar From 8e421caba16d566dd46ff96dd9b0b0957b7400f7 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 19 Sep 2014 15:04:21 -0700 Subject: [PATCH 72/85] terraform: show each tainted ID --- terraform/context_test.go | 51 +++++++++++++++++++++++++++++++++++++ terraform/state.go | 10 ++++---- terraform/terraform_test.go | 24 +++++++++++++++-- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/terraform/context_test.go b/terraform/context_test.go index 780815bbb..8319f0da3 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1939,6 +1939,57 @@ func TestContextPlan_taint(t *testing.T) { } } +func TestContextPlan_multiple_taint(t *testing.T) { + c := testConfig(t, "plan-taint") + p := testProvider("aws") + p.DiffFn = testDiffFn + s := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{"num": "2"}, + }, + }, + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Tainted: []*InstanceState{ + &InstanceState{ + ID: "baz", + }, + &InstanceState{ + ID: "zip", + }, + }, + }, + }, + }, + }, + } + ctx := testContext(t, &ContextOpts{ + Config: c, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + State: s, + }) + + plan, err := ctx.Plan(nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(plan.String()) + expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr) + if actual != expected { + t.Fatalf("bad:\n%s", actual) + } +} + func TestContextPlan_varMultiCountOne(t *testing.T) { c := testConfig(t, "plan-var-multi-count-one") p := testProvider("aws") diff --git a/terraform/state.go b/terraform/state.go index 7122d3763..d018362b8 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -125,11 +125,7 @@ func (s *State) String() string { id = rs.Primary.ID } if id == "" { - if len(rs.Tainted) > 0 { - id = rs.Tainted[0].ID - } else { - id = "" - } + id = "" } taintStr := "" @@ -159,6 +155,10 @@ func (s *State) String() string { buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) } + for idx, t := range rs.Tainted { + buf.WriteString(fmt.Sprintf(" Tainted ID %d = %s\n", idx+1, t.ID)) + } + if len(rs.Dependencies) > 0 { buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) for _, dep := range rs.Dependencies { diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index e86c3f5e1..d2228f884 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -138,7 +138,8 @@ aws_instance.foo: const testTerraformApplyProvisionerFailStr = ` aws_instance.bar: (1 tainted) - ID = foo + ID = + Tainted ID 1 = foo aws_instance.foo: ID = foo num = 2 @@ -501,7 +502,26 @@ DESTROY/CREATE: aws_instance.bar STATE: aws_instance.bar: (1 tainted) - ID = baz + ID = + Tainted ID 1 = baz +aws_instance.foo: + ID = bar + num = 2 +` + +const testTerraformPlanMultipleTaintStr = ` +DIFF: + +DESTROY/CREATE: aws_instance.bar + foo: "" => "2" + type: "" => "aws_instance" + +STATE: + +aws_instance.bar: (2 tainted) + ID = + Tainted ID 1 = baz + Tainted ID 2 = zip aws_instance.foo: ID = bar num = 2 From 1d96373a54c25bf9a19ca60203bf2fe13fcd094d Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 19 Sep 2014 16:15:52 -0700 Subject: [PATCH 73/85] terraform: deepcopy should not alloc when nil --- terraform/state.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index d018362b8..327fd8351 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -94,6 +94,9 @@ func (s *State) deepcopy() *State { // prune is used to remove any resources that are no longer required func (s *State) prune() { + if s == nil { + return + } for _, mod := range s.Modules { mod.prune() } @@ -391,12 +394,14 @@ func (i *InstanceState) deepcopy() *InstanceState { return nil } n := &InstanceState{ - ID: i.ID, - Attributes: make(map[string]string, len(i.Attributes)), - Ephemeral: *i.Ephemeral.deepcopy(), + ID: i.ID, + Ephemeral: *i.Ephemeral.deepcopy(), } - for k, v := range i.Attributes { - n.Attributes[k] = v + if i.Attributes != nil { + n.Attributes = make(map[string]string, len(i.Attributes)) + for k, v := range i.Attributes { + n.Attributes[k] = v + } } return n } @@ -489,11 +494,12 @@ func (e *EphemeralState) deepcopy() *EphemeralState { if e == nil { return nil } - n := &EphemeralState{ - ConnInfo: make(map[string]string, len(e.ConnInfo)), - } - for k, v := range e.ConnInfo { - n.ConnInfo[k] = v + n := &EphemeralState{} + if e.ConnInfo != nil { + n.ConnInfo = make(map[string]string, len(e.ConnInfo)) + for k, v := range e.ConnInfo { + n.ConnInfo[k] = v + } } return n } From 5e0765c24a1c44acfa311e6e4d4db7370ab337cf Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 19 Sep 2014 16:24:17 -0700 Subject: [PATCH 74/85] terraform: Refresh handles tainted instances --- terraform/context.go | 56 ++++++++++++++++++++++++++++----------- terraform/context_test.go | 53 ++++++++++++++++++++++++++++++++++-- terraform/state.go | 2 +- 3 files changed, 93 insertions(+), 18 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 2fac4d1a1..39e37129a 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -17,6 +17,11 @@ import ( // tree internally on the Terraform structure. type genericWalkFunc func(*Resource) error +// This function is used to implement a walked for a resource that +// visits each instance, handling tainted resources first, then the +// primary. +type instanceWalkFunc func(*Resource, bool, **InstanceState) error + // Context represents all the context that Terraform needs in order to // perform operations on infrastructure. This structure is built using // ContextOpts and NewContext. See the documentation for those. @@ -231,6 +236,9 @@ func (c *Context) Refresh() (*State, error) { v := c.acquireRun() defer c.releaseRun(v) + // Update our state + c.state = c.state.deepcopy() + g, err := Graph(&GraphOpts{ Config: c.config, Providers: c.providers, @@ -241,10 +249,10 @@ func (c *Context) Refresh() (*State, error) { return c.state, err } - // Update our state - c.state = c.state.deepcopy() - err = g.Walk(c.refreshWalkFn()) + + // Prune the state + c.state.prune() return c.state, err } @@ -885,18 +893,19 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } func (c *Context) refreshWalkFn() depgraph.WalkFunc { - cb := func(r *Resource) error { - if r.State.Primary == nil || r.State.Primary.ID == "" { + cb := func(r *Resource, tainted bool, inst **InstanceState) error { + if *inst == nil || (*inst).ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) return nil } + state := *inst for _, h := range c.hooks { - handleHook(h.PreRefresh(r.Id, r.State.Primary)) + handleHook(h.PreRefresh(r.Id, state)) } info := &InstanceInfo{Type: r.State.Type} - is, err := r.Provider.Refresh(info, r.State.Primary) + is, err := r.Provider.Refresh(info, state) if err != nil { return err } @@ -905,24 +914,23 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { is.init() } - c.sl.Lock() + // Update the state + *inst = is + // TODO: Handle other modules + c.sl.Lock() mod := c.state.RootModule() - if len(r.State.Tainted) == 0 && (is == nil || is.ID == "") { - delete(mod.Resources, r.Id) - } else { - mod.Resources[r.Id].Primary = is - } + mod.Resources[r.Id] = r.State c.sl.Unlock() for _, h := range c.hooks { - handleHook(h.PostRefresh(r.Id, r.State.Primary)) + handleHook(h.PostRefresh(r.Id, is)) } return nil } - return c.genericWalkFn(cb) + return c.genericWalkFn(instanceWalk(cb)) } func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc { @@ -1009,6 +1017,24 @@ func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc } } +//type instanceWalkFunc func(*Resource, bool, **InstanceState) error +func instanceWalk(cb instanceWalkFunc) genericWalkFunc { + return func(r *Resource) error { + // Handle the tainted resources first + for idx := range r.State.Tainted { + if err := cb(r, true, &r.State.Tainted[idx]); err != nil { + return err + } + } + + // Handle the primary resource + if r.State.Primary == nil { + r.State.init() + } + return cb(r, false, &r.State.Primary) + } +} + func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { // This will keep track of whether we're stopped or not var stop uint32 = 0 diff --git a/terraform/context_test.go b/terraform/context_test.go index 8319f0da3..e155bef17 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2055,7 +2055,7 @@ func TestContextRefresh(t *testing.T) { t.Fatalf("bad: %#v", p.RefreshState) } if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { - t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) + t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn) } for _, r := range mod.Resources { @@ -2219,13 +2219,62 @@ func TestContextRefresh_state(t *testing.T) { t.Fatal("refresh should be called") } if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) { - t.Fatalf("bad: %#v", p.RefreshState) + t.Fatalf("bad: %#v %#v", p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) } if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { t.Fatalf("bad: %#v", mod.Resources) } } +func TestContextRefresh_tainted(t *testing.T) { + p := testProvider("aws") + c := testConfig(t, "refresh-basic") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Tainted: []*InstanceState{ + &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + }, + } + ctx := testContext(t, &ContextOpts{ + Config: c, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + State: state, + }) + + p.RefreshFn = nil + p.RefreshReturn = &InstanceState{ + ID: "foo", + } + + s, err := ctx.Refresh() + if err != nil { + t.Fatalf("err: %s", err) + } + originalMod := state.RootModule() + mod := s.RootModule() + if !p.RefreshCalled { + t.Fatal("refresh should be called") + } + if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) { + t.Fatalf("bad: %#v %#v", p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) + } + if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Tainted[0], p.RefreshReturn) { + t.Fatalf("bad: %#v", mod.Resources) + } +} + func TestContextRefresh_vars(t *testing.T) { p := testProvider("aws") c := testConfig(t, "refresh-vars") diff --git a/terraform/state.go b/terraform/state.go index 327fd8351..18cfa6200 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -418,8 +418,8 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { result := s.deepcopy() if result == nil { result = new(InstanceState) - result.init() } + result.init() if s != nil { for k, v := range s.Attributes { From f89c2c5ff0f80b011a3ec6001bf6ace237fed010 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Sep 2014 21:29:48 -0600 Subject: [PATCH 75/85] terraform: graph tainted resources into the graph --- terraform/graph.go | 86 +++++++++++-- terraform/graph_test.go | 113 ++++++++++++++++++ terraform/resource.go | 1 + terraform/test-fixtures/graph-tainted/main.tf | 18 +++ 4 files changed, 209 insertions(+), 9 deletions(-) create mode 100644 terraform/test-fixtures/graph-tainted/main.tf diff --git a/terraform/graph.go b/terraform/graph.go index b8c16c9e5..d303fcc81 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -106,15 +106,19 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) { g := new(depgraph.Graph) // First, build the initial resource graph. This only has the resources - // and no dependencies. + // and no dependencies. This only adds resources that are in the config + // and not "orphans" (that are in the state, but not in the config). graphAddConfigResources(g, opts.Config, opts.State) // Add explicit dependsOn dependencies to the graph graphAddExplicitDeps(g) - // Next, add the state orphans if we have any if opts.State != nil { + // Next, add the state orphans if we have any graphAddOrphans(g, opts.Config, opts.State) + + // Add tainted resources if we have any. + graphAddTainted(g, opts.State) } // Map the provider configurations to all of the resources @@ -750,15 +754,12 @@ func graphAddVariableDeps(g *depgraph.Graph) { var vars map[string]config.InterpolatedVariable switch m := n.Meta.(type) { case *GraphNodeResource: - // Ignore orphan nodes - if m.Orphan { - continue + if m.Config != nil { + // Handle the resource variables + vars = m.Config.RawConfig.Variables + nounAddVariableDeps(g, n, vars, false) } - // Handle the resource variables - vars = m.Config.RawConfig.Variables - nounAddVariableDeps(g, n, vars, false) - // Handle the variables of the resource provisioners for _, p := range m.Resource.Provisioners { vars = p.RawConfig.Variables @@ -778,6 +779,73 @@ func graphAddVariableDeps(g *depgraph.Graph) { } } +// graphAddTainted adds the tainted instances to the graph. +func graphAddTainted(g *depgraph.Graph, s *State) { + // TODO: Handle other modules + mod := s.ModuleByPath(rootModulePath) + if mod == nil { + return + } + + var nlist []*depgraph.Noun + for k, rs := range mod.Resources { + // If we have no tainted resources, continue on + if len(rs.Tainted) == 0 { + continue + } + + // Find the untainted resource of this in the noun list + var untainted *depgraph.Noun + for _, n := range g.Nouns { + if n.Name == k { + untainted = n + break + } + } + + for i, _ := range rs.Tainted { + name := fmt.Sprintf("%s (tainted #%d)", k, i+1) + + // Add each of the tainted resources to the graph, and encode + // a dependency from the non-tainted resource to this so that + // tainted resources are always destroyed first. + noun := &depgraph.Noun{ + Name: name, + Meta: &GraphNodeResource{ + Index: -1, + Type: rs.Type, + Resource: &Resource{ + Id: k, + State: rs, + Config: NewResourceConfig(nil), + Diff: &InstanceDiff{Destroy: true}, + Tainted: true, + TaintedIndex: i, + }, + }, + } + + // Append it to the list so we handle it later + nlist = append(nlist, noun) + + // If we have an untainted version, then make sure to add + // the dependency. + if untainted != nil { + dep := &depgraph.Dependency{ + Name: name, + Source: untainted, + Target: noun, + } + + untainted.Deps = append(untainted.Deps, dep) + } + } + } + + // Add the nouns to the graph + g.Nouns = append(g.Nouns, nlist...) +} + // nounAddVariableDeps updates the dependencies of a noun given // a set of associated variable values func nounAddVariableDeps( diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 69adb5a00..8501b7c3a 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -112,6 +112,81 @@ func TestGraph_state(t *testing.T) { } } +func TestGraph_tainted(t *testing.T) { + config := testConfig(t, "graph-tainted") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + Tainted: []*InstanceState{ + &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + }, + } + + g, err := Graph(&GraphOpts{Config: config, State: state}) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTerraformGraphTaintedStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) + } +} + +func TestGraph_taintedMulti(t *testing.T) { + config := testConfig(t, "graph-tainted") + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + Tainted: []*InstanceState{ + &InstanceState{ + ID: "bar", + }, + &InstanceState{ + ID: "baz", + }, + }, + }, + }, + }, + }, + } + + g, err := Graph(&GraphOpts{Config: config, State: state}) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTerraformGraphTaintedMultiStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) + } +} + func TestGraphFull(t *testing.T) { rpAws := new(MockResourceProvider) rpOS := new(MockResourceProvider) @@ -715,6 +790,44 @@ root root -> openstack_floating_ip.random ` +const testTerraformGraphTaintedStr = ` +root: root +aws_instance.web + aws_instance.web -> aws_instance.web (tainted #1) + aws_instance.web -> aws_security_group.firewall + aws_instance.web -> provider.aws +aws_instance.web (tainted #1) + aws_instance.web (tainted #1) -> provider.aws +aws_security_group.firewall + aws_security_group.firewall -> provider.aws +provider.aws +root + root -> aws_instance.web + root -> aws_instance.web (tainted #1) + root -> aws_security_group.firewall +` + +const testTerraformGraphTaintedMultiStr = ` +root: root +aws_instance.web + aws_instance.web -> aws_instance.web (tainted #1) + aws_instance.web -> aws_instance.web (tainted #2) + aws_instance.web -> aws_security_group.firewall + aws_instance.web -> provider.aws +aws_instance.web (tainted #1) + aws_instance.web (tainted #1) -> provider.aws +aws_instance.web (tainted #2) + aws_instance.web (tainted #2) -> provider.aws +aws_security_group.firewall + aws_security_group.firewall -> provider.aws +provider.aws +root + root -> aws_instance.web + root -> aws_instance.web (tainted #1) + root -> aws_instance.web (tainted #2) + root -> aws_security_group.firewall +` + const testTerraformGraphCountOrphanStr = ` root: root aws_instance.web diff --git a/terraform/resource.go b/terraform/resource.go index 18277db10..225cf5f59 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -33,6 +33,7 @@ type Resource struct { State *ResourceState Provisioners []*ResourceProvisionerConfig Tainted bool + TaintedIndex int } // Vars returns the mapping of variables that should be replaced in diff --git a/terraform/test-fixtures/graph-tainted/main.tf b/terraform/test-fixtures/graph-tainted/main.tf new file mode 100644 index 000000000..da7eb0a79 --- /dev/null +++ b/terraform/test-fixtures/graph-tainted/main.tf @@ -0,0 +1,18 @@ +variable "foo" { + default = "bar" + description = "bar" +} + +provider "aws" { + foo = "${openstack_floating_ip.random.value}" +} + +resource "aws_security_group" "firewall" {} + +resource "aws_instance" "web" { + ami = "${var.foo}" + security_groups = [ + "foo", + "${aws_security_group.firewall.foo}" + ] +} From 157843725db843eb9d259fc9399baea444d9918d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Sep 2014 22:28:13 -0600 Subject: [PATCH 76/85] terraform: refreshing tainted resources works --- terraform/context.go | 23 +++++++++++++++-------- terraform/context_test.go | 19 ++++++++++++------- terraform/state.go | 8 +++++++- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 39e37129a..eb12e102d 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -893,19 +893,23 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } func (c *Context) refreshWalkFn() depgraph.WalkFunc { - cb := func(r *Resource, tainted bool, inst **InstanceState) error { - if *inst == nil || (*inst).ID == "" { + cb := func(r *Resource) error { + is := r.State.Primary + if r.Tainted { + is = r.State.Tainted[r.TaintedIndex] + } + + if is == nil || is.ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) return nil } - state := *inst for _, h := range c.hooks { - handleHook(h.PreRefresh(r.Id, state)) + handleHook(h.PreRefresh(r.Id, is)) } info := &InstanceInfo{Type: r.State.Type} - is, err := r.Provider.Refresh(info, state) + is, err := r.Provider.Refresh(info, is) if err != nil { return err } @@ -914,8 +918,11 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { is.init() } - // Update the state - *inst = is + if r.Tainted { + r.State.Tainted[r.TaintedIndex] = is + } else { + r.State.Primary = is + } // TODO: Handle other modules c.sl.Lock() @@ -930,7 +937,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { return nil } - return c.genericWalkFn(instanceWalk(cb)) + return c.genericWalkFn(cb) } func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc { diff --git a/terraform/context_test.go b/terraform/context_test.go index e155bef17..d5858d64c 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2235,6 +2235,7 @@ func TestContextRefresh_tainted(t *testing.T) { Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.web": &ResourceState{ + Type: "aws_instance", Tainted: []*InstanceState{ &InstanceState{ ID: "bar", @@ -2262,16 +2263,14 @@ func TestContextRefresh_tainted(t *testing.T) { if err != nil { t.Fatalf("err: %s", err) } - originalMod := state.RootModule() - mod := s.RootModule() if !p.RefreshCalled { t.Fatal("refresh should be called") } - if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) { - t.Fatalf("bad: %#v %#v", p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) - } - if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Tainted[0], p.RefreshReturn) { - t.Fatalf("bad: %#v", mod.Resources) + + actual := strings.TrimSpace(s.String()) + expected := strings.TrimSpace(testContextRefreshTaintedStr) + if actual != expected { + t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) } } @@ -2476,3 +2475,9 @@ root root -> aws_instance.bar root -> aws_instance.foo ` + +const testContextRefreshTaintedStr = ` +aws_instance.web: (1 tainted) + ID = + Tainted ID 1 = foo +` diff --git a/terraform/state.go b/terraform/state.go index 18cfa6200..b0cd16c54 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -364,6 +364,12 @@ func (s *ResourceState) GoString() string { return fmt.Sprintf("*%#v", *s) } +func (s *ResourceState) String() string { + var buf bytes.Buffer + buf.WriteString(fmt.Sprintf("Type = %s", s.Type)) + return buf.String() +} + // InstanceState is used to track the unique state information belonging // to a given instance. type InstanceState struct { @@ -451,7 +457,7 @@ func (i *InstanceState) GoString() string { func (i *InstanceState) String() string { var buf bytes.Buffer - if i.ID == "" { + if i == nil || i.ID == "" { return "" } From 10b5661bc31d731c0cea0efd0f23541a56463d3b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Sep 2014 22:35:29 -0600 Subject: [PATCH 77/85] terraform: planning tainted resources works --- terraform/context.go | 7 ++++++- terraform/graph.go | 9 +++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index eb12e102d..4c7a6ae0d 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -759,6 +759,11 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { result.init() cb := func(r *Resource) error { + if r.Tainted && r.TaintedIndex > -1 { + // No-op this. We somewhat magically diff this later. + return nil + } + var diff *InstanceDiff is := r.State.Primary @@ -895,7 +900,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { is := r.State.Primary - if r.Tainted { + if r.Tainted && r.TaintedIndex > -1 { is = r.State.Tainted[r.TaintedIndex] } diff --git a/terraform/graph.go b/terraform/graph.go index d303fcc81..2a2ad496c 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -271,10 +271,11 @@ func graphAddConfigResources( Type: r.Type, Config: r, Resource: &Resource{ - Id: name, - State: state, - Config: NewResourceConfig(r.RawConfig), - Tainted: len(state.Tainted) > 0, + Id: name, + State: state, + Config: NewResourceConfig(r.RawConfig), + Tainted: len(state.Tainted) > 0, + TaintedIndex: -1, }, }, } From 06c862a379d6623a0225046f941a8ecd16bf9737 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Sep 2014 22:47:53 -0600 Subject: [PATCH 78/85] terraform: tainted things all work --- terraform/context.go | 13 +++++++++---- terraform/diff.go | 7 ++++--- terraform/graph.go | 3 +++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 4c7a6ae0d..5498b7407 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -620,8 +620,13 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } } - // Update the primary instance - r.State.Primary = is + if r.Tainted && r.TaintedIndex > -1 { + // Update the tainted resource. + r.State.Tainted[r.TaintedIndex] = is + } else { + // Update the primary resource + r.State.Primary = is + } // Update the resulting diff c.sl.Lock() @@ -760,7 +765,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { cb := func(r *Resource) error { if r.Tainted && r.TaintedIndex > -1 { - // No-op this. We somewhat magically diff this later. + // We don't diff tainted resources. return nil } @@ -807,7 +812,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { if r.Tainted { // Tainted resources must also be destroyed log.Printf("[DEBUG] %s: Tainted, marking for destroy", r.Id) - diff.Destroy = true + diff.DestroyTainted = true } if diff.RequiresNew() && is != nil && is.ID != "" { diff --git a/terraform/diff.go b/terraform/diff.go index 64518f51f..39425ce3a 100644 --- a/terraform/diff.go +++ b/terraform/diff.go @@ -99,7 +99,7 @@ func (d *Diff) String() string { rdiff := d.Resources[name] crud := "UPDATE" - if rdiff.RequiresNew() && rdiff.Destroy { + if rdiff.RequiresNew() && (rdiff.Destroy || rdiff.DestroyTainted) { crud = "DESTROY/CREATE" } else if rdiff.Destroy { crud = "DESTROY" @@ -154,8 +154,9 @@ func (d *Diff) String() string { // InstanceDiff is the diff of a resource from some state to another. type InstanceDiff struct { - Attributes map[string]*ResourceAttrDiff - Destroy bool + Attributes map[string]*ResourceAttrDiff + Destroy bool + DestroyTainted bool once sync.Once } diff --git a/terraform/graph.go b/terraform/graph.go index 2a2ad496c..179bdb8b5 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -338,6 +338,9 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { if !ok { continue } + if rn.Resource.Tainted && rn.Resource.TaintedIndex > -1 { + continue + } rd, ok := d.Resources[rn.Resource.Id] if !ok { From 53c23266ca47e77ad330f6a94ae9724c3cf92c38 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Sep 2014 23:01:51 -0600 Subject: [PATCH 79/85] terraform: add Info field to Resource, remove from Node --- terraform/context.go | 16 +++++----------- terraform/context_test.go | 2 +- terraform/graph.go | 21 ++++++++++----------- terraform/resource.go | 1 + terraform/terraform_test.go | 2 +- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 5498b7407..29d23ee21 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -543,10 +543,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return err } - info := &InstanceInfo{ - Type: r.State.Type, - } - diff, err = r.Provider.Diff(info, r.State.Primary, r.Config) + diff, err = r.Provider.Diff(r.Info, r.State.Primary, r.Config) if err != nil { return err } @@ -591,8 +588,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // With the completed diff, apply! log.Printf("[DEBUG] %s: Executing Apply", r.Id) - info := &InstanceInfo{Type: r.State.Type} - is, applyerr := r.Provider.Apply(info, r.State.Primary, diff) + is, applyerr := r.Provider.Apply(r.Info, r.State.Primary, diff) var errs []error if applyerr != nil { @@ -798,8 +794,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { state.Type = r.State.Type } state.init() - info := &InstanceInfo{Type: state.Type} - diff, err = r.Provider.Diff(info, state.Primary, r.Config) + diff, err = r.Provider.Diff(r.Info, state.Primary, r.Config) if err != nil { return err } @@ -918,8 +913,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { handleHook(h.PreRefresh(r.Id, is)) } - info := &InstanceInfo{Type: r.State.Type} - is, err := r.Provider.Refresh(info, is) + is, err := r.Provider.Refresh(r.Info, is) if err != nil { return err } @@ -977,7 +971,7 @@ func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc log.Printf("[INFO] Validating resource: %s", rn.Resource.Id) ws, es := rn.Resource.Provider.ValidateResource( - rn.Type, rn.Resource.Config) + rn.Resource.Info.Type, rn.Resource.Config) for i, w := range ws { ws[i] = fmt.Sprintf("'%s' warning: %s", rn.Resource.Id, w) } diff --git a/terraform/context_test.go b/terraform/context_test.go index d5858d64c..28f23bb1f 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1887,7 +1887,7 @@ func TestContextPlan_state(t *testing.T) { actual := strings.TrimSpace(plan.String()) expected := strings.TrimSpace(testTerraformPlanStateStr) if actual != expected { - t.Fatalf("bad:\n%s", actual) + t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) } } diff --git a/terraform/graph.go b/terraform/graph.go index 179bdb8b5..4af03a315 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -56,7 +56,6 @@ const GraphRootNode = "root" // or a component of a resource. type GraphNodeResource struct { Index int - Type string Config *config.Resource Orphan bool Resource *Resource @@ -268,10 +267,10 @@ func graphAddConfigResources( Name: name, Meta: &GraphNodeResource{ Index: index, - Type: r.Type, Config: r, Resource: &Resource{ Id: name, + Info: &InstanceInfo{Type: r.Type}, State: state, Config: NewResourceConfig(r.RawConfig), Tainted: len(state.Tainted) > 0, @@ -552,11 +551,11 @@ func graphAddMissingResourceProviders( continue } - prefixes := matchingPrefixes(rn.Type, ps) + prefixes := matchingPrefixes(rn.Resource.Info.Type, ps) if len(prefixes) == 0 { errs = append(errs, fmt.Errorf( "No matching provider for type: %s", - rn.Type)) + rn.Resource.Info.Type)) continue } @@ -608,10 +607,10 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { Name: k, Meta: &GraphNodeResource{ Index: -1, - Type: rs.Type, Orphan: true, Resource: &Resource{ Id: k, + Info: &InstanceInfo{Type: rs.Type}, State: rs, Config: NewResourceConfig(nil), }, @@ -676,7 +675,7 @@ func graphAddProviderConfigs(g *depgraph.Graph, c *config.Config) { // Look up the provider config for this resource pcName := config.ProviderConfigName( - resourceNode.Type, c.ProviderConfigs) + resourceNode.Resource.Info.Type, c.ProviderConfigs) if pcName == "" { continue } @@ -817,9 +816,9 @@ func graphAddTainted(g *depgraph.Graph, s *State) { Name: name, Meta: &GraphNodeResource{ Index: -1, - Type: rs.Type, Resource: &Resource{ Id: k, + Info: &InstanceInfo{Type: rs.Type}, State: rs, Config: NewResourceConfig(nil), Diff: &InstanceDiff{Destroy: true}, @@ -987,18 +986,18 @@ func graphMapResourceProviders(g *depgraph.Graph) error { panic(fmt.Sprintf( "Resource provider ID not found: %s (type: %s)", rn.ResourceProviderID, - rn.Type)) + rn.Resource.Info.Type)) } var provider ResourceProvider for _, k := range rpn.ProviderKeys { // Only try this provider if it has the right prefix - if !strings.HasPrefix(rn.Type, k) { + if !strings.HasPrefix(rn.Resource.Info.Type, k) { continue } rp := rpn.Providers[k] - if ProviderSatisfies(rp, rn.Type) { + if ProviderSatisfies(rp, rn.Resource.Info.Type) { provider = rp break } @@ -1007,7 +1006,7 @@ func graphMapResourceProviders(g *depgraph.Graph) error { if provider == nil { errs = append(errs, fmt.Errorf( "Resource provider not found for resource type '%s'", - rn.Type)) + rn.Resource.Info.Type)) continue } diff --git a/terraform/resource.go b/terraform/resource.go index 225cf5f59..a625b5732 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -27,6 +27,7 @@ type ResourceProvisionerConfig struct { // wants to reach. type Resource struct { Id string + Info *InstanceInfo Config *ResourceConfig Diff *InstanceDiff Provider ResourceProvider diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index d2228f884..c8df4c2a1 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -484,7 +484,7 @@ CREATE: aws_instance.bar type: "" => "aws_instance" UPDATE: aws_instance.foo num: "" => "2" - type: "" => "" + type: "" => "aws_instance" STATE: From 13a4818867281e8194b48c255763a4528844444f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Sep 2014 17:02:31 -0700 Subject: [PATCH 80/85] terraform: add flags field --- terraform/context.go | 55 +++++++++++++++---------------------------- terraform/graph.go | 34 +++++++++++--------------- terraform/resource.go | 13 +++++++++- 3 files changed, 45 insertions(+), 57 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index 29d23ee21..f9ed271b8 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -616,7 +616,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } } - if r.Tainted && r.TaintedIndex > -1 { + if r.Flags&FlagTainted != 0 { // Update the tainted resource. r.State.Tainted[r.TaintedIndex] = is } else { @@ -667,7 +667,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { c.sl.Unlock() // Update the state for the resource itself - r.Tainted = tainted + if tainted { + r.Flags &^= FlagPrimary + r.Flags &^= FlagHasTainted + r.Flags |= FlagTainted + } for _, h := range c.hooks { handleHook(h.PostApply(r.Id, r.State.Primary, applyerr)) @@ -760,7 +764,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { result.init() cb := func(r *Resource) error { - if r.Tainted && r.TaintedIndex > -1 { + if r.Flags&FlagTainted != 0 { // We don't diff tainted resources. return nil } @@ -773,7 +777,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { handleHook(h.PreDiff(r.Id, is)) } - if r.Config == nil { + if r.Flags&FlagOrphan != 0 { log.Printf("[DEBUG] %s: Orphan, marking for destroy", r.Id) // This is an orphan (no config), so we mark it to be destroyed @@ -788,7 +792,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { log.Printf("[DEBUG] %s: Executing diff", r.Id) var err error state := r.State - if r.Tainted { + if r.Flags&FlagHasTainted != 0 { // If we're tainted, we pretend to create a new thing. state = new(ResourceState) state.Type = r.State.Type @@ -804,9 +808,10 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { diff = new(InstanceDiff) } - if r.Tainted { - // Tainted resources must also be destroyed - log.Printf("[DEBUG] %s: Tainted, marking for destroy", r.Id) + if r.Flags&FlagHasTainted != 0 { + // This primary has a tainted resource, so just mark for + // destroy... + log.Printf("[DEBUG] %s: Tainted children, marking for destroy", r.Id) diff.DestroyTainted = true } @@ -900,7 +905,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { is := r.State.Primary - if r.Tainted && r.TaintedIndex > -1 { + if r.Flags&FlagTainted != 0 { is = r.State.Tainted[r.TaintedIndex] } @@ -922,7 +927,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { is.init() } - if r.Tainted { + if r.Flags&FlagTainted != 0 { r.State.Tainted[r.TaintedIndex] = is } else { r.State.Primary = is @@ -965,7 +970,7 @@ func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc } // Don't validate orphans since they never have a config - if rn.Orphan { + if rn.Resource.Flags&FlagOrphan != 0 { return nil } @@ -1028,24 +1033,6 @@ func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc } } -//type instanceWalkFunc func(*Resource, bool, **InstanceState) error -func instanceWalk(cb instanceWalkFunc) genericWalkFunc { - return func(r *Resource) error { - // Handle the tainted resources first - for idx := range r.State.Tainted { - if err := cb(r, true, &r.State.Tainted[idx]); err != nil { - return err - } - } - - // Handle the primary resource - if r.State.Primary == nil { - r.State.init() - } - return cb(r, false, &r.State.Primary) - } -} - func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { // This will keep track of whether we're stopped or not var stop uint32 = 0 @@ -1099,14 +1086,10 @@ func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { rn := n.Meta.(*GraphNodeResource) // Make sure that at least some resource configuration is set - if !rn.Orphan { - if rn.Config == nil { - rn.Resource.Config = new(ResourceConfig) - } else { - rn.Resource.Config = NewResourceConfig(rn.Config.RawConfig) - } + if rn.Config == nil { + rn.Resource.Config = new(ResourceConfig) } else { - rn.Resource.Config = nil + rn.Resource.Config = NewResourceConfig(rn.Config.RawConfig) } // Handle recovery of special panic scenarios diff --git a/terraform/graph.go b/terraform/graph.go index 4af03a315..8911a5c9b 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -57,7 +57,6 @@ const GraphRootNode = "root" type GraphNodeResource struct { Index int Config *config.Resource - Orphan bool Resource *Resource ResourceProviderID string } @@ -263,18 +262,22 @@ func graphAddConfigResources( } } + flags := FlagPrimary + if len(state.Tainted) > 0 { + flags |= FlagHasTainted + } + resourceNouns[i] = &depgraph.Noun{ Name: name, Meta: &GraphNodeResource{ Index: index, Config: r, Resource: &Resource{ - Id: name, - Info: &InstanceInfo{Type: r.Type}, - State: state, - Config: NewResourceConfig(r.RawConfig), - Tainted: len(state.Tainted) > 0, - TaintedIndex: -1, + Id: name, + Info: &InstanceInfo{Type: r.Type}, + State: state, + Config: NewResourceConfig(r.RawConfig), + Flags: flags, }, }, } @@ -337,7 +340,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { if !ok { continue } - if rn.Resource.Tainted && rn.Resource.TaintedIndex > -1 { + if rn.Resource.Flags&FlagTainted != 0 { continue } @@ -387,15 +390,6 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { Source: n, Target: newN, }) - - // If the resource is tainted, mark the state as nil so - // that a fresh create is done. - if rn.Resource.Tainted { - rn.Resource.State = &ResourceState{ - Type: rn.Resource.State.Type, - } - rn.Resource.Tainted = false - } } rn.Resource.Diff = rd @@ -606,13 +600,13 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { noun := &depgraph.Noun{ Name: k, Meta: &GraphNodeResource{ - Index: -1, - Orphan: true, + Index: -1, Resource: &Resource{ Id: k, Info: &InstanceInfo{Type: rs.Type}, State: rs, Config: NewResourceConfig(nil), + Flags: FlagOrphan, }, }, } @@ -822,7 +816,7 @@ func graphAddTainted(g *depgraph.Graph, s *State) { State: rs, Config: NewResourceConfig(nil), Diff: &InstanceDiff{Destroy: true}, - Tainted: true, + Flags: FlagTainted, TaintedIndex: i, }, }, diff --git a/terraform/resource.go b/terraform/resource.go index a625b5732..2962e3491 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -33,10 +33,21 @@ type Resource struct { Provider ResourceProvider State *ResourceState Provisioners []*ResourceProvisionerConfig - Tainted bool + Flags ResourceFlag TaintedIndex int } +// ResourceKind specifies what kind of instance we're working with, whether +// its a primary instance, a tainted instance, or an orphan. +type ResourceFlag byte + +const ( + FlagPrimary ResourceFlag = 1 << iota + FlagTainted + FlagOrphan + FlagHasTainted +) + // Vars returns the mapping of variables that should be replaced in // configuration based on the attributes of this resource. func (r *Resource) Vars() map[string]string { From a3bb8435b7daf1b70d3798ce20716431d7ecc5c6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Sep 2014 09:42:37 -0700 Subject: [PATCH 81/85] terraform: remove unused --- terraform/context.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index f9ed271b8..cd4b74fcd 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -17,11 +17,6 @@ import ( // tree internally on the Terraform structure. type genericWalkFunc func(*Resource) error -// This function is used to implement a walked for a resource that -// visits each instance, handling tainted resources first, then the -// primary. -type instanceWalkFunc func(*Resource, bool, **InstanceState) error - // Context represents all the context that Terraform needs in order to // perform operations on infrastructure. This structure is built using // ContextOpts and NewContext. See the documentation for those. From 82e92e7024b24cfc5644d9fae977607a0230a0a2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Sep 2014 09:42:48 -0700 Subject: [PATCH 82/85] command: fmt --- command/refresh_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/refresh_test.go b/command/refresh_test.go index 1281f4c18..6ff99f9f1 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -5,8 +5,8 @@ import ( "os" "path/filepath" "reflect" - "testing" "strings" + "testing" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" From 73e2a43427b57d0d852c25110768879b18a8a782 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Sep 2014 22:08:21 -0700 Subject: [PATCH 83/85] terraform: don't put the ResourceState in Resource --- terraform/context.go | 169 +++++++++++++++++++------------------ terraform/graph.go | 46 +++++----- terraform/graph_dot.go | 2 +- terraform/graph_test.go | 8 +- terraform/resource.go | 4 +- terraform/resource_test.go | 8 +- 6 files changed, 122 insertions(+), 115 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index cd4b74fcd..813a4c5ca 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -126,15 +126,14 @@ func (c *Context) Apply() (*State, error) { } c.state.init() + // Initialize the state with all the resources + graphInitState(c.state, g) + // Walk log.Printf("[INFO] Apply walk starting") err = g.Walk(c.applyWalkFn()) log.Printf("[INFO] Apply walk complete") - // Encode the dependencies, this pushes the logical dependencies - // into the state so that we can recover it later. - EncodeDependencies(g) - // Prune the state so that we have as clean a state as possible c.state.prune() @@ -209,6 +208,9 @@ func (c *Context) Plan(opts *PlanOpts) (*Plan, error) { c.state = old }() + // Initialize the state with all the resources + graphInitState(c.state, g) + walkFn = c.planWalkFn(p) } @@ -244,6 +246,12 @@ func (c *Context) Refresh() (*State, error) { return c.state, err } + if c.state != nil { + // Initialize the state with all the resources + graphInitState(c.state, g) + } + + // Walk the graph err = g.Walk(c.refreshWalkFn()) // Prune the state @@ -529,8 +537,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return nil } - // Ensure the state is initialized - r.State.init() + is := r.State + if is == nil { + is = new(InstanceState) + } + is.init() if !diff.Destroy { // Since we need the configuration, interpolate the variables @@ -538,7 +549,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { return err } - diff, err = r.Provider.Diff(r.Info, r.State.Primary, r.Config) + diff, err = r.Provider.Diff(r.Info, is, r.Config) if err != nil { return err } @@ -578,12 +589,12 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } for _, h := range c.hooks { - handleHook(h.PreApply(r.Id, r.State.Primary, diff)) + handleHook(h.PreApply(r.Id, is, diff)) } // With the completed diff, apply! log.Printf("[DEBUG] %s: Executing Apply", r.Id) - is, applyerr := r.Provider.Apply(r.Info, r.State.Primary, diff) + is, applyerr := r.Provider.Apply(r.Info, is, diff) var errs []error if applyerr != nil { @@ -611,25 +622,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } } - if r.Flags&FlagTainted != 0 { - // Update the tainted resource. - r.State.Tainted[r.TaintedIndex] = is - } else { - // Update the primary resource - r.State.Primary = is - } - - // Update the resulting diff - c.sl.Lock() - - // TODO: Get other modules - mod := c.state.RootModule() - if is.ID == "" && len(r.State.Tainted) == 0 { - delete(mod.Resources, r.Id) - } else { - mod.Resources[r.Id] = r.State - } - c.sl.Unlock() + // Set the result state + r.State = is + c.persistState(r) // Invoke any provisioners we have defined. This is only done // if the resource was created, as updates or deletes do not @@ -638,9 +633,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { // Additionally, we need to be careful to not run this if there // was an error during the provider apply. tainted := false - if applyerr == nil && r.State.Primary.ID != "" && len(r.Provisioners) > 0 { + if applyerr == nil && is.ID != "" && len(r.Provisioners) > 0 { for _, h := range c.hooks { - handleHook(h.PreProvisionResource(r.Id, r.State.Primary)) + handleHook(h.PreProvisionResource(r.Id, is)) } if err := c.applyProvisioners(r, is); err != nil { @@ -649,27 +644,21 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc { } for _, h := range c.hooks { - handleHook(h.PostProvisionResource(r.Id, r.State.Primary)) + handleHook(h.PostProvisionResource(r.Id, is)) } } - c.sl.Lock() - if tainted { - log.Printf("[DEBUG] %s: Marking as tainted", r.Id) - r.State.Tainted = append(r.State.Tainted, r.State.Primary) - r.State.Primary = nil - } - c.sl.Unlock() - - // Update the state for the resource itself - if tainted { + // If we're tainted then we need to update some flags + if tainted && r.Flags&FlagTainted == 0 { r.Flags &^= FlagPrimary r.Flags &^= FlagHasTainted r.Flags |= FlagTainted + r.TaintedIndex = -1 + c.persistState(r) } for _, h := range c.hooks { - handleHook(h.PostApply(r.Id, r.State.Primary, applyerr)) + handleHook(h.PostApply(r.Id, is, applyerr)) } // Determine the new state and update variables @@ -766,7 +755,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { var diff *InstanceDiff - is := r.State.Primary + is := r.State for _, h := range c.hooks { handleHook(h.PreDiff(r.Id, is)) @@ -786,14 +775,15 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { // Get a diff from the newest state log.Printf("[DEBUG] %s: Executing diff", r.Id) var err error - state := r.State - if r.Flags&FlagHasTainted != 0 { + + diffIs := is + if diffIs == nil || r.Flags&FlagHasTainted != 0 { // If we're tainted, we pretend to create a new thing. - state = new(ResourceState) - state.Type = r.State.Type + diffIs = new(InstanceState) } - state.init() - diff, err = r.Provider.Diff(r.Info, state.Primary, r.Config) + diffIs.init() + + diff, err = r.Provider.Diff(r.Info, diffIs, r.Config) if err != nil { return err } @@ -846,23 +836,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc { is = is.MergeDiff(diff) } - // TODO(mitchellh): do we really need this? I had to do this because - // the pointer of r.State is shared with the original c.state - // which is now result.State, so modifying this was actually - // modifying the plan state, which is not what we want. I *think* - // this will be solved if we move to having InstanceState on - // type Resource rather than ResourceState, so I'm just going to - // keep this in here for now to get tests to work. - state := r.State.deepcopy() - state.Primary = is - - // Update our internal state so that variable computation works - c.sl.Lock() - defer c.sl.Unlock() - - // TODO: Handle other modules - mod := c.state.RootModule() - mod.Resources[r.Id] = state + // Set it so that it can be updated + r.State = is + c.persistState(r) return nil } @@ -883,7 +859,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } r := rn.Resource - if r.State.Primary != nil && r.State.Primary.ID != "" { + if r.State != nil && r.State.ID != "" { log.Printf("[DEBUG] %s: Making for destroy", r.Id) l.Lock() @@ -899,10 +875,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { - is := r.State.Primary - if r.Flags&FlagTainted != 0 { - is = r.State.Tainted[r.TaintedIndex] - } + is := r.State if is == nil || is.ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) @@ -922,17 +895,9 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { is.init() } - if r.Flags&FlagTainted != 0 { - r.State.Tainted[r.TaintedIndex] = is - } else { - r.State.Primary = is - } - - // TODO: Handle other modules - c.sl.Lock() - mod := c.state.RootModule() - mod.Resources[r.Id] = r.State - c.sl.Unlock() + // Set the updated state + r.State = is + c.persistState(r) for _, h := range c.hooks { handleHook(h.PostRefresh(r.Id, is)) @@ -1111,3 +1076,43 @@ func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { return nil } } + +func (c *Context) persistState(r *Resource) { + // Acquire a state lock around this whole thing since we're updating that + c.sl.Lock() + defer c.sl.Unlock() + + // If we have no state, then we don't persist. + if c.state == nil { + return + } + + // Get the state for this resource. The resource state should always + // exist because we call graphInitState before anything that could + // potentially call this. + module := c.state.RootModule() + rs := module.Resources[r.Id] + if rs == nil { + panic(fmt.Sprintf("nil ResourceState for ID: %s", r.Id)) + } + + // Assign the instance state to the proper location + if r.Flags&FlagTainted != 0 { + if r.TaintedIndex >= 0 { + // Tainted with a pre-existing index, just update that spot + rs.Tainted[r.TaintedIndex] = r.State + } else { + // Newly tainted, so append it to the list, update the + // index, and remove the primary. + rs.Tainted = append(rs.Tainted, r.State) + rs.Primary = nil + r.TaintedIndex = len(rs.Tainted) - 1 + } + } else { + // The primary instance, so just set it directly + rs.Primary = r.State + } + + // Do a pruning so that empty resources are not saved + rs.prune() +} diff --git a/terraform/graph.go b/terraform/graph.go index 8911a5c9b..4fcb5f1dc 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -172,24 +172,28 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) { return g, nil } -// EncodeDependencies is used to walk the graph and encode the -// logical dependency information into the resource state. This -// allows the dependency tree to be recovered from the state file -// such that orphaned resources will still be destroyed in the -// proper order. -func EncodeDependencies(g *depgraph.Graph) { +// graphInitState is used to initialize a State with a ResourceState +// for every resource. +// +// This method is very important to call because it will properly setup +// the ResourceState dependency information with data from the graph. This +// allows orphaned resources to be destroyed in the proper order. +func graphInitState(s *State, g *depgraph.Graph) { + // TODO: other modules + mod := s.RootModule() + for _, n := range g.Nouns { // Ignore any non-resource nodes rn, ok := n.Meta.(*GraphNodeResource) if !ok { continue } - - // Skip only if the resource has state - rs := rn.Resource - state := rs.State - if state == nil { - continue + r := rn.Resource + rs := mod.Resources[r.Id] + if rs == nil { + rs = new(ResourceState) + rs.init() + mod.Resources[r.Id] = rs } // Update the dependencies @@ -197,7 +201,7 @@ func EncodeDependencies(g *depgraph.Graph) { for _, dep := range n.Deps { switch target := dep.Target.Meta.(type) { case *GraphNodeResource: - if target.Resource.Id == rs.Id { + if target.Resource.Id == r.Id { continue } inject = append(inject, target.Resource.Id) @@ -212,7 +216,7 @@ func EncodeDependencies(g *depgraph.Graph) { } // Update the dependencies - state.Dependencies = inject + rs.Dependencies = inject } } @@ -275,7 +279,7 @@ func graphAddConfigResources( Resource: &Resource{ Id: name, Info: &InstanceInfo{Type: r.Type}, - State: state, + State: state.Primary, Config: NewResourceConfig(r.RawConfig), Flags: flags, }, @@ -604,7 +608,7 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { Resource: &Resource{ Id: k, Info: &InstanceInfo{Type: rs.Type}, - State: rs, + State: rs.Primary, Config: NewResourceConfig(nil), Flags: FlagOrphan, }, @@ -625,8 +629,8 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { rn := n.Meta.(*GraphNodeResource) // If we have no dependencies, then just continue - deps := rn.Resource.State.Dependencies - if len(deps) == 0 { + rs := mod.Resources[n.Name] + if len(rs.Dependencies) == 0 { continue } @@ -641,7 +645,7 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { continue } - for _, depName := range rn.Resource.State.Dependencies { + for _, depName := range rs.Dependencies { if rn2.Resource.Id != depName { continue } @@ -800,7 +804,7 @@ func graphAddTainted(g *depgraph.Graph, s *State) { } } - for i, _ := range rs.Tainted { + for i, is := range rs.Tainted { name := fmt.Sprintf("%s (tainted #%d)", k, i+1) // Add each of the tainted resources to the graph, and encode @@ -813,7 +817,7 @@ func graphAddTainted(g *depgraph.Graph, s *State) { Resource: &Resource{ Id: k, Info: &InstanceInfo{Type: rs.Type}, - State: rs, + State: is, Config: NewResourceConfig(nil), Diff: &InstanceDiff{Destroy: true}, Flags: FlagTainted, diff --git a/terraform/graph_dot.go b/terraform/graph_dot.go index b7db917d0..7b0d0d325 100644 --- a/terraform/graph_dot.go +++ b/terraform/graph_dot.go @@ -79,7 +79,7 @@ func graphDotAddResources(buf *bytes.Buffer, g *depgraph.Graph) { // green = create. Destroy is in the next section. var color, fillColor string if rn.Resource.Diff != nil && !rn.Resource.Diff.Empty() { - if rn.Resource.State != nil && rn.Resource.State.Primary.ID != "" { + if rn.Resource.State != nil && rn.Resource.State.ID != "" { color = "#FFFF00" fillColor = "#FFFF94" } else { diff --git a/terraform/graph_test.go b/terraform/graph_test.go index 8501b7c3a..a9170f6f9 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -516,7 +516,7 @@ func TestGraphAddDiff_destroy_counts(t *testing.T) { } } -func TestEncodeDependencies(t *testing.T) { +func TestGraphInitState(t *testing.T) { config := testConfig(t, "graph-basic") state := &State{ Modules: []*ModuleState{ @@ -546,7 +546,7 @@ func TestEncodeDependencies(t *testing.T) { } // This should encode the dependency information into the state - EncodeDependencies(g) + graphInitState(state, g) root := state.RootModule() web := root.Resources["aws_instance.web"] @@ -560,7 +560,7 @@ func TestEncodeDependencies(t *testing.T) { } } -func TestEncodeDependencies_Count(t *testing.T) { +func TestGraphInitState_Count(t *testing.T) { config := testConfig(t, "graph-count") state := &State{ Modules: []*ModuleState{ @@ -590,7 +590,7 @@ func TestEncodeDependencies_Count(t *testing.T) { } // This should encode the dependency information into the state - EncodeDependencies(g) + graphInitState(state, g) root := state.RootModule() web := root.Resources["aws_instance.web.0"] diff --git a/terraform/resource.go b/terraform/resource.go index 2962e3491..7923409ae 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -31,7 +31,7 @@ type Resource struct { Config *ResourceConfig Diff *InstanceDiff Provider ResourceProvider - State *ResourceState + State *InstanceState Provisioners []*ResourceProvisionerConfig Flags ResourceFlag TaintedIndex int @@ -56,7 +56,7 @@ func (r *Resource) Vars() map[string]string { } vars := make(map[string]string) - for ak, av := range r.State.Primary.Attributes { + for ak, av := range r.State.Attributes { vars[fmt.Sprintf("%s.%s", r.Id, ak)] = av } diff --git a/terraform/resource_test.go b/terraform/resource_test.go index b8afb4e5d..19ed56355 100644 --- a/terraform/resource_test.go +++ b/terraform/resource_test.go @@ -16,11 +16,9 @@ func TestResource_Vars(t *testing.T) { r = &Resource{ Id: "key", - State: &ResourceState{ - Primary: &InstanceState{ - Attributes: map[string]string{ - "foo": "bar", - }, + State: &InstanceState{ + Attributes: map[string]string{ + "foo": "bar", }, }, } From 7a9739658337faa37d5143aa71c0793e47259629 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Sep 2014 22:35:11 -0700 Subject: [PATCH 84/85] terraform: remove unused function --- terraform/resource.go | 15 --------------- terraform/resource_test.go | 25 ------------------------- 2 files changed, 40 deletions(-) diff --git a/terraform/resource.go b/terraform/resource.go index 7923409ae..573851026 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -48,21 +48,6 @@ const ( FlagHasTainted ) -// Vars returns the mapping of variables that should be replaced in -// configuration based on the attributes of this resource. -func (r *Resource) Vars() map[string]string { - if r.State == nil { - return nil - } - - vars := make(map[string]string) - for ak, av := range r.State.Attributes { - vars[fmt.Sprintf("%s.%s", r.Id, ak)] = av - } - - return vars -} - // ResourceConfig holds the configuration given for a resource. This is // done instead of a raw `map[string]interface{}` type so that rich // methods can be added to it to make dealing with it easier. diff --git a/terraform/resource_test.go b/terraform/resource_test.go index 19ed56355..17d4b5469 100644 --- a/terraform/resource_test.go +++ b/terraform/resource_test.go @@ -7,31 +7,6 @@ import ( "github.com/hashicorp/terraform/config" ) -func TestResource_Vars(t *testing.T) { - r := new(Resource) - - if len(r.Vars()) > 0 { - t.Fatalf("bad: %#v", r.Vars()) - } - - r = &Resource{ - Id: "key", - State: &InstanceState{ - Attributes: map[string]string{ - "foo": "bar", - }, - }, - } - - expected := map[string]string{ - "key.foo": "bar", - } - actual := r.Vars() - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: %#v", actual) - } -} - func TestResourceConfigGet(t *testing.T) { cases := []struct { Config map[string]interface{} From ca875f54573dada975418fc64c4bfb761c854bc3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Sep 2014 22:36:34 -0700 Subject: [PATCH 85/85] terraform: fix missing arg to Printf --- terraform/state.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/terraform/state.go b/terraform/state.go index b0cd16c54..f02794f7b 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -596,7 +596,11 @@ func upgradeV1State(old *StateV1) (*State, error) { // Warn if the resource uses Extra, as there is // no upgrade path for this! Now totally deprecated. if len(rs.Extra) > 0 { - log.Printf("[WARN] Resource %s uses deprecated attribute storage, state file upgrade may be incomplete.") + log.Printf( + "[WARN] Resource %s uses deprecated attribute "+ + "storage, state file upgrade may be incomplete.", + rs.ID, + ) } } return s, nil