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

View File

@ -201,6 +201,62 @@ func (p *shadowResourceProviderReal) Refresh(
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
// calls never affect real resources. This is paired with the "real" side
// which must be called properly to enable recording.
@ -219,21 +275,23 @@ type shadowResourceProviderShared struct {
// NOTE: Anytime a value is added here, be sure to add it to
// the Close() method so that it is closed.
CloseErr shadow.Value
Input shadow.Value
Validate shadow.Value
Configure shadow.Value
ValidateResource shadow.KeyedValue
Apply shadow.KeyedValue
Diff shadow.KeyedValue
Refresh shadow.KeyedValue
CloseErr shadow.Value
Input shadow.Value
Validate shadow.Value
Configure shadow.Value
ValidateResource shadow.KeyedValue
Apply shadow.KeyedValue
Diff shadow.KeyedValue
Refresh shadow.KeyedValue
ValidateDataSource shadow.KeyedValue
ReadDataDiff shadow.KeyedValue
}
func (p *shadowResourceProviderShared) Close() error {
closers := []io.Closer{
&p.CloseErr, &p.Input, &p.Validate,
&p.Configure, &p.ValidateResource, &p.Apply, &p.Diff,
&p.Refresh,
&p.Refresh, &p.ValidateDataSource, &p.ReadDataDiff,
}
for _, c := range closers {
@ -536,6 +594,94 @@ func (p *shadowResourceProviderShadow) Refresh(
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
@ -546,16 +692,6 @@ func (p *shadowResourceProviderShadow) ImportState(info *InstanceInfo, id string
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(
info *InstanceInfo,
d *InstanceDiff) (*InstanceState, error) {
@ -613,3 +749,21 @@ type shadowResourceProviderRefresh struct {
Result *InstanceState
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
}