Skip to content

Commit

Permalink
Merge pull request #1454 from hashicorp/f-copy-config
Browse files Browse the repository at this point in the history
terraform: copy RawConfigs to avoid races
  • Loading branch information
mitchellh committed Apr 9, 2015
2 parents f000418 + 06beab6 commit 8083098
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 4 deletions.
27 changes: 27 additions & 0 deletions config/raw_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"bytes"
"encoding/gob"
"sync"

"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast"
Expand Down Expand Up @@ -31,6 +32,7 @@ type RawConfig struct {
Interpolations []ast.Node
Variables map[string]InterpolatedVariable

lock sync.Mutex
config map[string]interface{}
unknownKeys []string
}
Expand All @@ -46,6 +48,20 @@ func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
return result, nil
}

// Copy returns a copy of this RawConfig, uninterpolated.
func (r *RawConfig) Copy() *RawConfig {
r.lock.Lock()
defer r.lock.Unlock()

result, err := NewRawConfig(r.Raw)
if err != nil {
panic("copy failed: " + err.Error())
}

result.Key = r.Key
return result
}

// Value returns the value of the configuration if this configuration
// has a Key set. If this does not have a Key set, nil will be returned.
func (r *RawConfig) Value() interface{} {
Expand All @@ -55,6 +71,8 @@ func (r *RawConfig) Value() interface{} {
}
}

r.lock.Lock()
defer r.lock.Unlock()
return r.Raw[r.Key]
}

Expand All @@ -81,6 +99,9 @@ func (r *RawConfig) Config() map[string]interface{} {
//
// If a variable key is missing, this will panic.
func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
r.lock.Lock()
defer r.lock.Unlock()

config := langEvalConfig(vs)
return r.interpolate(func(root ast.Node) (string, error) {
// We detect the variables again and check if the value of any
Expand Down Expand Up @@ -119,6 +140,9 @@ func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
// values in this config) and returns a new config. The original config
// is not modified.
func (r *RawConfig) Merge(other *RawConfig) *RawConfig {
r.lock.Lock()
defer r.lock.Unlock()

// Merge the raw configurations
raw := make(map[string]interface{})
for k, v := range r.Raw {
Expand Down Expand Up @@ -252,6 +276,9 @@ func (r *RawConfig) GobDecode(b []byte) error {
// tree of interpolated variables is recomputed on decode, since it is
// referentially transparent.
func (r *RawConfig) GobEncode() ([]byte, error) {
r.lock.Lock()
defer r.lock.Unlock()

data := gobRawConfig{
Key: r.Key,
Raw: r.Raw,
Expand Down
8 changes: 4 additions & 4 deletions terraform/transform_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Output: &provider,
})
vseq.Nodes = append(vseq.Nodes, &EvalInterpolate{
Config: n.Resource.RawConfig,
Config: n.Resource.RawConfig.Copy(),
Resource: resource,
Output: &resourceConfig,
})
Expand All @@ -189,7 +189,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Name: p.Type,
Output: &provisioner,
}, &EvalInterpolate{
Config: p.RawConfig,
Config: p.RawConfig.Copy(),
Resource: resource,
Output: &resourceConfig,
}, &EvalValidateProvisioner{
Expand Down Expand Up @@ -243,7 +243,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalInterpolate{
Config: n.Resource.RawConfig,
Config: n.Resource.RawConfig.Copy(),
Resource: resource,
Output: &resourceConfig,
},
Expand Down Expand Up @@ -354,7 +354,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
},

&EvalInterpolate{
Config: n.Resource.RawConfig,
Config: n.Resource.RawConfig.Copy(),
Resource: resource,
Output: &resourceConfig,
},
Expand Down

0 comments on commit 8083098

Please sign in to comment.