terraform: take into account dependency variables in diffs
This commit is contained in:
parent
8358e7dc1f
commit
d77a72ba84
|
@ -24,7 +24,7 @@ type ResourceProvider interface {
|
||||||
// Diff diffs a resource versus a desired state and returns
|
// Diff diffs a resource versus a desired state and returns
|
||||||
// a diff.
|
// a diff.
|
||||||
Diff(
|
Diff(
|
||||||
ResourceState,
|
*ResourceState,
|
||||||
map[string]interface{}) (ResourceDiff, error)
|
map[string]interface{}) (ResourceDiff, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ type MockResourceProvider struct {
|
||||||
ConfigureReturnWarnings []string
|
ConfigureReturnWarnings []string
|
||||||
ConfigureReturnError error
|
ConfigureReturnError error
|
||||||
DiffCalled bool
|
DiffCalled bool
|
||||||
DiffState ResourceState
|
DiffState *ResourceState
|
||||||
DiffDesired map[string]interface{}
|
DiffDesired map[string]interface{}
|
||||||
DiffFn func(ResourceState, map[string]interface{}) (ResourceDiff, error)
|
DiffFn func(*ResourceState, map[string]interface{}) (ResourceDiff, error)
|
||||||
DiffReturn ResourceDiff
|
DiffReturn ResourceDiff
|
||||||
DiffReturnError error
|
DiffReturnError error
|
||||||
ResourcesCalled bool
|
ResourcesCalled bool
|
||||||
|
@ -27,7 +27,7 @@ func (p *MockResourceProvider) Configure(c map[string]interface{}) ([]string, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MockResourceProvider) Diff(
|
func (p *MockResourceProvider) Diff(
|
||||||
state ResourceState,
|
state *ResourceState,
|
||||||
desired map[string]interface{}) (ResourceDiff, error) {
|
desired map[string]interface{}) (ResourceDiff, error) {
|
||||||
p.DiffCalled = true
|
p.DiffCalled = true
|
||||||
p.DiffState = state
|
p.DiffState = state
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
// State keeps track of a snapshot state-of-the-world that Terraform
|
// 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
|
// can use to keep track of what real world resources it is actually
|
||||||
// managing.
|
// managing.
|
||||||
type State struct {
|
type State struct {
|
||||||
resources map[string]ResourceState
|
resources map[string]*ResourceState
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) init() {
|
||||||
|
s.once.Do(func() {
|
||||||
|
s.resources = make(map[string]*ResourceState)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceState holds the state of a resource that is used so that
|
// ResourceState holds the state of a resource that is used so that
|
||||||
|
@ -33,7 +44,7 @@ type ResourceState struct {
|
||||||
// computeID.
|
// computeID.
|
||||||
func (s *ResourceState) MergeDiff(
|
func (s *ResourceState) MergeDiff(
|
||||||
d map[string]*ResourceAttrDiff,
|
d map[string]*ResourceAttrDiff,
|
||||||
computedID string) ResourceState {
|
computedID string) *ResourceState {
|
||||||
var result ResourceState
|
var result ResourceState
|
||||||
if s != nil {
|
if s != nil {
|
||||||
result = *s
|
result = *s
|
||||||
|
@ -54,5 +65,5 @@ func (s *ResourceState) MergeDiff(
|
||||||
result.Attributes[k] = diff.New
|
result.Attributes[k] = diff.New
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,19 @@ func (t *Terraform) Refresh(*State) (*State, error) {
|
||||||
|
|
||||||
func (t *Terraform) diffWalkFn(
|
func (t *Terraform) diffWalkFn(
|
||||||
state *State, result *Diff) depgraph.WalkFunc {
|
state *State, result *Diff) depgraph.WalkFunc {
|
||||||
var resultLock sync.Mutex
|
var l sync.RWMutex
|
||||||
|
|
||||||
|
// Initialize the state since we always read it
|
||||||
|
if state == nil {
|
||||||
|
state = new(State)
|
||||||
|
state.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the result diff so we can write to it
|
||||||
|
result.init()
|
||||||
|
|
||||||
|
// This is the value that will be used for computed properties
|
||||||
|
computedId := "computed"
|
||||||
|
|
||||||
return func(n *depgraph.Noun) error {
|
return func(n *depgraph.Noun) error {
|
||||||
// If it is the root node, ignore
|
// If it is the root node, ignore
|
||||||
|
@ -155,7 +167,14 @@ func (t *Terraform) diffWalkFn(
|
||||||
panic(fmt.Sprintf("No provider for resource: %s", r.Id()))
|
panic(fmt.Sprintf("No provider for resource: %s", r.Id()))
|
||||||
}
|
}
|
||||||
|
|
||||||
var rs ResourceState
|
l.RLock()
|
||||||
|
rs := state.resources[r.Id()]
|
||||||
|
vs := t.replaceVariables(r, state)
|
||||||
|
if len(vs) > 0 {
|
||||||
|
r = r.ReplaceVariables(vs)
|
||||||
|
}
|
||||||
|
l.RUnlock()
|
||||||
|
|
||||||
diff, err := p.Diff(rs, r.Config)
|
diff, err := p.Diff(rs, r.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -166,16 +185,38 @@ func (t *Terraform) diffWalkFn(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a lock and modify the resulting diff
|
// Acquire a lock since this function is called in parallel
|
||||||
resultLock.Lock()
|
l.Lock()
|
||||||
defer resultLock.Unlock()
|
defer l.Unlock()
|
||||||
result.init()
|
|
||||||
|
// Update the resulting diff
|
||||||
result.Resources[r.Id()] = diff.Attributes
|
result.Resources[r.Id()] = diff.Attributes
|
||||||
|
|
||||||
|
// Update the state for child dependencies
|
||||||
|
state.resources[r.Id()] = rs.MergeDiff(diff.Attributes, computedId)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replaceVariables will return the mapping of variable replacements to
|
||||||
|
// apply for a given resource with a given state.
|
||||||
|
func (t *Terraform) replaceVariables(
|
||||||
|
r *config.Resource,
|
||||||
|
s *State) map[string]string {
|
||||||
|
result := make(map[string]string)
|
||||||
|
for k, v := range t.variables {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
for n, rs := range s.resources {
|
||||||
|
for attrK, attrV := range rs.Attributes {
|
||||||
|
result[fmt.Sprintf("%s.%s", n, attrK)] = attrV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// matchingPrefixes takes a resource type and a set of resource
|
// matchingPrefixes takes a resource type and a set of resource
|
||||||
// providers we know about by prefix and returns a list of prefixes
|
// providers we know about by prefix and returns a list of prefixes
|
||||||
// that might be valid for that resource.
|
// that might be valid for that resource.
|
||||||
|
|
|
@ -141,7 +141,7 @@ func testProviderFunc(n string, rs []string) ResourceProviderFactory {
|
||||||
|
|
||||||
return func() (ResourceProvider, error) {
|
return func() (ResourceProvider, error) {
|
||||||
diffFn := func(
|
diffFn := func(
|
||||||
_ ResourceState,
|
_ *ResourceState,
|
||||||
c map[string]interface{}) (ResourceDiff, error) {
|
c map[string]interface{}) (ResourceDiff, error) {
|
||||||
var diff ResourceDiff
|
var diff ResourceDiff
|
||||||
diff.Attributes = make(map[string]*ResourceAttrDiff)
|
diff.Attributes = make(map[string]*ResourceAttrDiff)
|
||||||
|
@ -205,7 +205,7 @@ func testTerraform(t *testing.T, name string) *Terraform {
|
||||||
|
|
||||||
const testTerraformDiffStr = `
|
const testTerraformDiffStr = `
|
||||||
aws_instance.bar
|
aws_instance.bar
|
||||||
foo: "" => "${aws_instance.foo.num}"
|
foo: "" => "2"
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
num: "" => "2"
|
num: "" => "2"
|
||||||
`
|
`
|
||||||
|
|
Loading…
Reference in New Issue