terraform: ResourceProvider.ReadDataDiff (shadow)

This commit is contained in:
Mitchell Hashimoto 2016-10-09 12:12:18 +08:00
parent 31f8d13678
commit b0801bf125
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 174 additions and 21 deletions

View File

@ -2,7 +2,6 @@ package terraform
import ( import (
"fmt" "fmt"
"reflect"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/mitchellh/copystructure" "github.com/mitchellh/copystructure"
@ -85,7 +84,7 @@ func shadowContextVerify(real, shadow *Context) error {
} }
// Compare the diffs // Compare the diffs
if !reflect.DeepEqual(real.diff, shadow.diff) { if !real.diff.Equal(shadow.diff) {
result = multierror.Append(result, fmt.Errorf( result = multierror.Append(result, fmt.Errorf(
"Real and shadow diffs do not match! "+ "Real and shadow diffs do not match! "+
"Real diff:\n\n%s\n\n"+ "Real diff:\n\n%s\n\n"+

View File

@ -201,6 +201,62 @@ func (p *shadowResourceProviderReal) Refresh(
return result, err return result, err
} }
func (p *shadowResourceProviderReal) ValidateDataSource(
t string, c *ResourceConfig) ([]string, []error) {
key := t
configCopy := c.DeepCopy()
// Real operation
warns, errs := p.ResourceProvider.ValidateDataSource(t, c)
// Get the result
raw, ok := p.Shared.ValidateDataSource.ValueOk(key)
if !ok {
raw = new(shadowResourceProviderValidateDataSourceWrapper)
}
wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper)
if !ok {
// If this fails then we just continue with our day... the shadow
// will fail to but there isn't much we can do.
log.Printf(
"[ERROR] unknown value in ValidateDataSource shadow value: %#v", raw)
return warns, errs
}
// Lock the wrapper for writing and record our call
wrapper.Lock()
defer wrapper.Unlock()
wrapper.Calls = append(wrapper.Calls, &shadowResourceProviderValidateDataSource{
Config: configCopy,
Warns: warns,
Errors: errs,
})
// Set it
p.Shared.ValidateDataSource.SetValue(key, wrapper)
// Return the result
return warns, errs
}
func (p *shadowResourceProviderReal) ReadDataDiff(
info *InstanceInfo,
desired *ResourceConfig) (*InstanceDiff, error) {
// These have to be copied before the call since call can modify
desiredCopy := desired.DeepCopy()
result, err := p.ResourceProvider.ReadDataDiff(info, desired)
p.Shared.ReadDataDiff.SetValue(info.uniqueId(), &shadowResourceProviderReadDataDiff{
Desired: desiredCopy,
Result: result.DeepCopy(),
ResultErr: err,
})
return result, err
}
// shadowResourceProviderShadow is the shadow resource provider. Function // shadowResourceProviderShadow is the shadow resource provider. Function
// calls never affect real resources. This is paired with the "real" side // calls never affect real resources. This is paired with the "real" side
// which must be called properly to enable recording. // which must be called properly to enable recording.
@ -227,13 +283,15 @@ type shadowResourceProviderShared struct {
Apply shadow.KeyedValue Apply shadow.KeyedValue
Diff shadow.KeyedValue Diff shadow.KeyedValue
Refresh shadow.KeyedValue Refresh shadow.KeyedValue
ValidateDataSource shadow.KeyedValue
ReadDataDiff shadow.KeyedValue
} }
func (p *shadowResourceProviderShared) Close() error { func (p *shadowResourceProviderShared) Close() error {
closers := []io.Closer{ closers := []io.Closer{
&p.CloseErr, &p.Input, &p.Validate, &p.CloseErr, &p.Input, &p.Validate,
&p.Configure, &p.ValidateResource, &p.Apply, &p.Diff, &p.Configure, &p.ValidateResource, &p.Apply, &p.Diff,
&p.Refresh, &p.Refresh, &p.ValidateDataSource, &p.ReadDataDiff,
} }
for _, c := range closers { for _, c := range closers {
@ -536,6 +594,94 @@ func (p *shadowResourceProviderShadow) Refresh(
return result.Result, result.ResultErr return result.Result, result.ResultErr
} }
func (p *shadowResourceProviderShadow) ValidateDataSource(
t string, c *ResourceConfig) ([]string, []error) {
// Unique key
key := t
// Get the initial value
raw := p.Shared.ValidateDataSource.Value(key)
// Find a validation with our configuration
var result *shadowResourceProviderValidateDataSource
for {
// Get the value
if raw == nil {
p.ErrorLock.Lock()
defer p.ErrorLock.Unlock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Unknown 'ValidateDataSource' call for %q:\n\n%#v",
key, c))
return nil, nil
}
wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper)
if !ok {
p.ErrorLock.Lock()
defer p.ErrorLock.Unlock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Unknown 'ValidateDataSource' shadow value: %#v", raw))
return nil, nil
}
// Look for the matching call with our configuration
wrapper.RLock()
for _, call := range wrapper.Calls {
if call.Config.Equal(c) {
result = call
break
}
}
wrapper.RUnlock()
// If we found a result, exit
if result != nil {
break
}
// Wait for a change so we can get the wrapper again
raw = p.Shared.ValidateDataSource.WaitForChange(key)
}
return result.Warns, result.Errors
}
func (p *shadowResourceProviderShadow) ReadDataDiff(
info *InstanceInfo,
desired *ResourceConfig) (*InstanceDiff, error) {
// Unique key
key := info.uniqueId()
raw := p.Shared.ReadDataDiff.Value(key)
if raw == nil {
p.ErrorLock.Lock()
defer p.ErrorLock.Unlock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Unknown 'ReadDataDiff' call for %q:\n\n%#v",
key, desired))
return nil, nil
}
result, ok := raw.(*shadowResourceProviderReadDataDiff)
if !ok {
p.ErrorLock.Lock()
defer p.ErrorLock.Unlock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Unknown 'ReadDataDiff' shadow value: %#v", raw))
return nil, nil
}
// Compare the parameters, which should be identical
if !desired.Equal(result.Desired) {
p.ErrorLock.Lock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"ReadDataDiff %q had unequal configs (real, then shadow):\n\n%#v\n\n%#v",
key, result.Desired, desired))
p.ErrorLock.Unlock()
}
return result.Result, result.ResultErr
}
// TODO // TODO
// TODO // TODO
// TODO // TODO
@ -546,16 +692,6 @@ func (p *shadowResourceProviderShadow) ImportState(info *InstanceInfo, id string
return nil, nil return nil, nil
} }
func (p *shadowResourceProviderShadow) ValidateDataSource(t string, c *ResourceConfig) ([]string, []error) {
return nil, nil
}
func (p *shadowResourceProviderShadow) ReadDataDiff(
info *InstanceInfo,
desired *ResourceConfig) (*InstanceDiff, error) {
return nil, nil
}
func (p *shadowResourceProviderShadow) ReadDataApply( func (p *shadowResourceProviderShadow) ReadDataApply(
info *InstanceInfo, info *InstanceInfo,
d *InstanceDiff) (*InstanceState, error) { d *InstanceDiff) (*InstanceState, error) {
@ -613,3 +749,21 @@ type shadowResourceProviderRefresh struct {
Result *InstanceState Result *InstanceState
ResultErr error ResultErr error
} }
type shadowResourceProviderValidateDataSourceWrapper struct {
sync.RWMutex
Calls []*shadowResourceProviderValidateDataSource
}
type shadowResourceProviderValidateDataSource struct {
Config *ResourceConfig
Warns []string
Errors []error
}
type shadowResourceProviderReadDataDiff struct {
Desired *ResourceConfig
Result *InstanceDiff
ResultErr error
}