diff --git a/terraform/diff.go b/terraform/diff.go index d566d2582..33b4a9896 100644 --- a/terraform/diff.go +++ b/terraform/diff.go @@ -400,6 +400,21 @@ func (d *InstanceDiff) Empty() bool { return !d.Destroy && !d.DestroyTainted && len(d.Attributes) == 0 } +// Equal compares two diffs for exact equality. +// +// This is different from the Same comparison that is supported which +// checks for operation equality taking into account computed values. Equal +// instead checks for exact equality. +func (d *InstanceDiff) Equal(d2 *InstanceDiff) bool { + // If one is nil, they must both be nil + if d == nil || d2 == nil { + return d == d2 + } + + // Use DeepEqual + return reflect.DeepEqual(d, d2) +} + // DeepCopy performs a deep copy of all parts of the InstanceDiff func (d *InstanceDiff) DeepCopy() *InstanceDiff { copy, err := copystructure.Config{Lock: true}.Copy(d) diff --git a/terraform/shadow_resource_provider.go b/terraform/shadow_resource_provider.go index 3ced39fcc..0355bd78e 100644 --- a/terraform/shadow_resource_provider.go +++ b/terraform/shadow_resource_provider.go @@ -254,6 +254,22 @@ func (p *shadowResourceProviderReal) ReadDataDiff( return result, err } +func (p *shadowResourceProviderReal) ReadDataApply( + info *InstanceInfo, + diff *InstanceDiff) (*InstanceState, error) { + // Thse have to be copied before the call since call can modify + diffCopy := diff.DeepCopy() + + result, err := p.ResourceProvider.ReadDataApply(info, diff) + p.Shared.ReadDataApply.SetValue(info.uniqueId(), &shadowResourceProviderReadDataApply{ + Diff: diffCopy, + Result: result.DeepCopy(), + ResultErr: err, + }) + + return result, err +} + // shadowResourceProviderShadow is the shadow resource provider. Function // calls never affect real resources. This is paired with the "real" side // which must be called properly to enable recording. @@ -282,6 +298,7 @@ type shadowResourceProviderShared struct { Refresh shadow.KeyedValue ValidateDataSource shadow.KeyedValue ReadDataDiff shadow.KeyedValue + ReadDataApply shadow.KeyedValue } func (p *shadowResourceProviderShared) Close() error { @@ -679,6 +696,42 @@ func (p *shadowResourceProviderShadow) ReadDataDiff( return result.Result, result.ResultErr } +func (p *shadowResourceProviderShadow) ReadDataApply( + info *InstanceInfo, + d *InstanceDiff) (*InstanceState, error) { + // Unique key + key := info.uniqueId() + raw := p.Shared.ReadDataApply.Value(key) + if raw == nil { + p.ErrorLock.Lock() + defer p.ErrorLock.Unlock() + p.Error = multierror.Append(p.Error, fmt.Errorf( + "Unknown 'ReadDataApply' call for %q:\n\n%#v", + key, d)) + return nil, nil + } + + result, ok := raw.(*shadowResourceProviderReadDataApply) + if !ok { + p.ErrorLock.Lock() + defer p.ErrorLock.Unlock() + p.Error = multierror.Append(p.Error, fmt.Errorf( + "Unknown 'ReadDataApply' shadow value: %#v", raw)) + return nil, nil + } + + // Compare the parameters, which should be identical + if !d.Equal(result.Diff) { + p.ErrorLock.Lock() + p.Error = multierror.Append(p.Error, fmt.Errorf( + "ReadDataApply: unequal diffs (real, then shadow):\n\n%#v\n\n%#v", + result.Diff, d)) + p.ErrorLock.Unlock() + } + + return result.Result, result.ResultErr +} + // TODO // TODO // TODO @@ -689,12 +742,6 @@ func (p *shadowResourceProviderShadow) ImportState(info *InstanceInfo, id string return nil, nil } -func (p *shadowResourceProviderShadow) ReadDataApply( - info *InstanceInfo, - d *InstanceDiff) (*InstanceState, error) { - return nil, nil -} - // The structs for the various function calls are put below. These structs // are used to carry call information across the real/shadow boundaries. @@ -764,3 +811,9 @@ type shadowResourceProviderReadDataDiff struct { Result *InstanceDiff ResultErr error } + +type shadowResourceProviderReadDataApply struct { + Diff *InstanceDiff + Result *InstanceState + ResultErr error +}