terraform: resource provider must never return pointers to same data

This is a requirement for the parallelism of Terraform to work sanely.
We could deep copy every result but I think this would be unrealistic
and impose a performance cost when it isn't necessary in most cases.
This commit is contained in:
Mitchell Hashimoto 2016-10-17 16:29:24 -07:00
parent baa59ff75d
commit e2c415a87e
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
3 changed files with 24 additions and 6 deletions

View File

@ -1088,6 +1088,10 @@ func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
t.Fatalf("missing diff for data.aws_data_resource.foo") t.Fatalf("missing diff for data.aws_data_resource.foo")
} }
// This is added by the diff but we want to verify that we got
// the same diff as above minus the dynamic stuff.
delete(iDiff.Attributes, "id")
if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same { if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same {
t.Fatalf( t.Fatalf(
"incorrect diff for data.data_resource.foo\ngot: %#v\nwant: %#v", "incorrect diff for data.data_resource.foo\ngot: %#v\nwant: %#v",

View File

@ -3,6 +3,12 @@ package terraform
// ResourceProvider is an interface that must be implemented by any // ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in // resource provider: the thing that creates and manages the resources in
// a Terraform configuration. // a Terraform configuration.
//
// Important implementation note: All returned pointers, such as
// *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
// shared data. Terraform is highly parallel and assumes that this data is safe
// to read/write in parallel so it must be unique references. Note that it is
// safe to return arguments as results, however.
type ResourceProvider interface { type ResourceProvider interface {
/********************************************************************* /*********************************************************************
* Functions related to the provider * Functions related to the provider

View File

@ -157,7 +157,7 @@ func (p *MockResourceProvider) Apply(
return p.ApplyFn(info, state, diff) return p.ApplyFn(info, state, diff)
} }
return p.ApplyReturn, p.ApplyReturnError return p.ApplyReturn.DeepCopy(), p.ApplyReturnError
} }
func (p *MockResourceProvider) Diff( func (p *MockResourceProvider) Diff(
@ -175,7 +175,7 @@ func (p *MockResourceProvider) Diff(
return p.DiffFn(info, state, desired) return p.DiffFn(info, state, desired)
} }
return p.DiffReturn, p.DiffReturnError return p.DiffReturn.DeepCopy(), p.DiffReturnError
} }
func (p *MockResourceProvider) Refresh( func (p *MockResourceProvider) Refresh(
@ -192,7 +192,7 @@ func (p *MockResourceProvider) Refresh(
return p.RefreshFn(info, s) return p.RefreshFn(info, s)
} }
return p.RefreshReturn, p.RefreshReturnError return p.RefreshReturn.DeepCopy(), p.RefreshReturnError
} }
func (p *MockResourceProvider) Resources() []ResourceType { func (p *MockResourceProvider) Resources() []ResourceType {
@ -214,7 +214,15 @@ func (p *MockResourceProvider) ImportState(info *InstanceInfo, id string) ([]*In
return p.ImportStateFn(info, id) return p.ImportStateFn(info, id)
} }
return p.ImportStateReturn, p.ImportStateReturnError var result []*InstanceState
if p.ImportStateReturn != nil {
result = make([]*InstanceState, len(p.ImportStateReturn))
for i, v := range p.ImportStateReturn {
result[i] = v.DeepCopy()
}
}
return result, p.ImportStateReturnError
} }
func (p *MockResourceProvider) ValidateDataSource(t string, c *ResourceConfig) ([]string, []error) { func (p *MockResourceProvider) ValidateDataSource(t string, c *ResourceConfig) ([]string, []error) {
@ -245,7 +253,7 @@ func (p *MockResourceProvider) ReadDataDiff(
return p.ReadDataDiffFn(info, desired) return p.ReadDataDiffFn(info, desired)
} }
return p.ReadDataDiffReturn, p.ReadDataDiffReturnError return p.ReadDataDiffReturn.DeepCopy(), p.ReadDataDiffReturnError
} }
func (p *MockResourceProvider) ReadDataApply( func (p *MockResourceProvider) ReadDataApply(
@ -262,7 +270,7 @@ func (p *MockResourceProvider) ReadDataApply(
return p.ReadDataApplyFn(info, d) return p.ReadDataApplyFn(info, d)
} }
return p.ReadDataApplyReturn, p.ReadDataApplyReturnError return p.ReadDataApplyReturn.DeepCopy(), p.ReadDataApplyReturnError
} }
func (p *MockResourceProvider) DataSources() []DataSource { func (p *MockResourceProvider) DataSources() []DataSource {