github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/terraform/shadow_resource_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  	"github.com/hashicorp/terraform/helper/shadow"
    11  )
    12  
    13  // shadowResourceProvider implements ResourceProvider for the shadow
    14  // eval context defined in eval_context_shadow.go.
    15  //
    16  // This is used to verify behavior with a real provider. This shouldn't
    17  // be used directly.
    18  type shadowResourceProvider interface {
    19  	ResourceProvider
    20  	Shadow
    21  }
    22  
    23  // newShadowResourceProvider creates a new shadowed ResourceProvider.
    24  //
    25  // This will assume a well behaved real ResourceProvider. For example,
    26  // it assumes that the `Resources` call underneath doesn't change values
    27  // since once it is called on the real provider, it will be cached and
    28  // returned in the shadow since number of calls to that shouldn't affect
    29  // actual behavior.
    30  //
    31  // However, with calls like Apply, call order is taken into account,
    32  // parameters are checked for equality, etc.
    33  func newShadowResourceProvider(p ResourceProvider) (ResourceProvider, shadowResourceProvider) {
    34  	// Create the shared data
    35  	shared := shadowResourceProviderShared{}
    36  
    37  	// Create the real provider that does actual work
    38  	real := &shadowResourceProviderReal{
    39  		ResourceProvider: p,
    40  		Shared:           &shared,
    41  	}
    42  
    43  	// Create the shadow that watches the real value
    44  	shadow := &shadowResourceProviderShadow{
    45  		Shared: &shared,
    46  
    47  		resources:   p.Resources(),
    48  		dataSources: p.DataSources(),
    49  	}
    50  
    51  	return real, shadow
    52  }
    53  
    54  // shadowResourceProviderReal is the real resource provider. Function calls
    55  // to this will perform real work. This records the parameters and return
    56  // values and call order for the shadow to reproduce.
    57  type shadowResourceProviderReal struct {
    58  	ResourceProvider
    59  
    60  	Shared *shadowResourceProviderShared
    61  }
    62  
    63  func (p *shadowResourceProviderReal) Close() error {
    64  	var result error
    65  	if c, ok := p.ResourceProvider.(ResourceProviderCloser); ok {
    66  		result = c.Close()
    67  	}
    68  
    69  	p.Shared.CloseErr.SetValue(result)
    70  	return result
    71  }
    72  
    73  func (p *shadowResourceProviderReal) Input(
    74  	input UIInput, c *ResourceConfig) (*ResourceConfig, error) {
    75  	cCopy := c.DeepCopy()
    76  
    77  	result, err := p.ResourceProvider.Input(input, c)
    78  	p.Shared.Input.SetValue(&shadowResourceProviderInput{
    79  		Config:    cCopy,
    80  		Result:    result.DeepCopy(),
    81  		ResultErr: err,
    82  	})
    83  
    84  	return result, err
    85  }
    86  
    87  func (p *shadowResourceProviderReal) Validate(c *ResourceConfig) ([]string, []error) {
    88  	warns, errs := p.ResourceProvider.Validate(c)
    89  	p.Shared.Validate.SetValue(&shadowResourceProviderValidate{
    90  		Config:     c.DeepCopy(),
    91  		ResultWarn: warns,
    92  		ResultErr:  errs,
    93  	})
    94  
    95  	return warns, errs
    96  }
    97  
    98  func (p *shadowResourceProviderReal) Configure(c *ResourceConfig) error {
    99  	cCopy := c.DeepCopy()
   100  
   101  	err := p.ResourceProvider.Configure(c)
   102  	p.Shared.Configure.SetValue(&shadowResourceProviderConfigure{
   103  		Config: cCopy,
   104  		Result: err,
   105  	})
   106  
   107  	return err
   108  }
   109  
   110  func (p *shadowResourceProviderReal) Stop() error {
   111  	return p.ResourceProvider.Stop()
   112  }
   113  
   114  func (p *shadowResourceProviderReal) ValidateResource(
   115  	t string, c *ResourceConfig) ([]string, []error) {
   116  	key := t
   117  	configCopy := c.DeepCopy()
   118  
   119  	// Real operation
   120  	warns, errs := p.ResourceProvider.ValidateResource(t, c)
   121  
   122  	// Initialize to ensure we always have a wrapper with a lock
   123  	p.Shared.ValidateResource.Init(
   124  		key, &shadowResourceProviderValidateResourceWrapper{})
   125  
   126  	// Get the result
   127  	raw := p.Shared.ValidateResource.Value(key)
   128  	wrapper, ok := raw.(*shadowResourceProviderValidateResourceWrapper)
   129  	if !ok {
   130  		// If this fails then we just continue with our day... the shadow
   131  		// will fail to but there isn't much we can do.
   132  		log.Printf(
   133  			"[ERROR] unknown value in ValidateResource shadow value: %#v", raw)
   134  		return warns, errs
   135  	}
   136  
   137  	// Lock the wrapper for writing and record our call
   138  	wrapper.Lock()
   139  	defer wrapper.Unlock()
   140  
   141  	wrapper.Calls = append(wrapper.Calls, &shadowResourceProviderValidateResource{
   142  		Config: configCopy,
   143  		Warns:  warns,
   144  		Errors: errs,
   145  	})
   146  
   147  	// With it locked, call SetValue again so that it triggers WaitForChange
   148  	p.Shared.ValidateResource.SetValue(key, wrapper)
   149  
   150  	// Return the result
   151  	return warns, errs
   152  }
   153  
   154  func (p *shadowResourceProviderReal) Apply(
   155  	info *InstanceInfo,
   156  	state *InstanceState,
   157  	diff *InstanceDiff) (*InstanceState, error) {
   158  	// Thse have to be copied before the call since call can modify
   159  	stateCopy := state.DeepCopy()
   160  	diffCopy := diff.DeepCopy()
   161  
   162  	result, err := p.ResourceProvider.Apply(info, state, diff)
   163  	p.Shared.Apply.SetValue(info.uniqueId(), &shadowResourceProviderApply{
   164  		State:     stateCopy,
   165  		Diff:      diffCopy,
   166  		Result:    result.DeepCopy(),
   167  		ResultErr: err,
   168  	})
   169  
   170  	return result, err
   171  }
   172  
   173  func (p *shadowResourceProviderReal) Diff(
   174  	info *InstanceInfo,
   175  	state *InstanceState,
   176  	desired *ResourceConfig) (*InstanceDiff, error) {
   177  	// Thse have to be copied before the call since call can modify
   178  	stateCopy := state.DeepCopy()
   179  	desiredCopy := desired.DeepCopy()
   180  
   181  	result, err := p.ResourceProvider.Diff(info, state, desired)
   182  	p.Shared.Diff.SetValue(info.uniqueId(), &shadowResourceProviderDiff{
   183  		State:     stateCopy,
   184  		Desired:   desiredCopy,
   185  		Result:    result.DeepCopy(),
   186  		ResultErr: err,
   187  	})
   188  
   189  	return result, err
   190  }
   191  
   192  func (p *shadowResourceProviderReal) Refresh(
   193  	info *InstanceInfo,
   194  	state *InstanceState) (*InstanceState, error) {
   195  	// Thse have to be copied before the call since call can modify
   196  	stateCopy := state.DeepCopy()
   197  
   198  	result, err := p.ResourceProvider.Refresh(info, state)
   199  	p.Shared.Refresh.SetValue(info.uniqueId(), &shadowResourceProviderRefresh{
   200  		State:     stateCopy,
   201  		Result:    result.DeepCopy(),
   202  		ResultErr: err,
   203  	})
   204  
   205  	return result, err
   206  }
   207  
   208  func (p *shadowResourceProviderReal) ValidateDataSource(
   209  	t string, c *ResourceConfig) ([]string, []error) {
   210  	key := t
   211  	configCopy := c.DeepCopy()
   212  
   213  	// Real operation
   214  	warns, errs := p.ResourceProvider.ValidateDataSource(t, c)
   215  
   216  	// Initialize
   217  	p.Shared.ValidateDataSource.Init(
   218  		key, &shadowResourceProviderValidateDataSourceWrapper{})
   219  
   220  	// Get the result
   221  	raw := p.Shared.ValidateDataSource.Value(key)
   222  	wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper)
   223  	if !ok {
   224  		// If this fails then we just continue with our day... the shadow
   225  		// will fail to but there isn't much we can do.
   226  		log.Printf(
   227  			"[ERROR] unknown value in ValidateDataSource shadow value: %#v", raw)
   228  		return warns, errs
   229  	}
   230  
   231  	// Lock the wrapper for writing and record our call
   232  	wrapper.Lock()
   233  	defer wrapper.Unlock()
   234  
   235  	wrapper.Calls = append(wrapper.Calls, &shadowResourceProviderValidateDataSource{
   236  		Config: configCopy,
   237  		Warns:  warns,
   238  		Errors: errs,
   239  	})
   240  
   241  	// Set it
   242  	p.Shared.ValidateDataSource.SetValue(key, wrapper)
   243  
   244  	// Return the result
   245  	return warns, errs
   246  }
   247  
   248  func (p *shadowResourceProviderReal) ReadDataDiff(
   249  	info *InstanceInfo,
   250  	desired *ResourceConfig) (*InstanceDiff, error) {
   251  	// These have to be copied before the call since call can modify
   252  	desiredCopy := desired.DeepCopy()
   253  
   254  	result, err := p.ResourceProvider.ReadDataDiff(info, desired)
   255  	p.Shared.ReadDataDiff.SetValue(info.uniqueId(), &shadowResourceProviderReadDataDiff{
   256  		Desired:   desiredCopy,
   257  		Result:    result.DeepCopy(),
   258  		ResultErr: err,
   259  	})
   260  
   261  	return result, err
   262  }
   263  
   264  func (p *shadowResourceProviderReal) ReadDataApply(
   265  	info *InstanceInfo,
   266  	diff *InstanceDiff) (*InstanceState, error) {
   267  	// Thse have to be copied before the call since call can modify
   268  	diffCopy := diff.DeepCopy()
   269  
   270  	result, err := p.ResourceProvider.ReadDataApply(info, diff)
   271  	p.Shared.ReadDataApply.SetValue(info.uniqueId(), &shadowResourceProviderReadDataApply{
   272  		Diff:      diffCopy,
   273  		Result:    result.DeepCopy(),
   274  		ResultErr: err,
   275  	})
   276  
   277  	return result, err
   278  }
   279  
   280  // shadowResourceProviderShadow is the shadow resource provider. Function
   281  // calls never affect real resources. This is paired with the "real" side
   282  // which must be called properly to enable recording.
   283  type shadowResourceProviderShadow struct {
   284  	Shared *shadowResourceProviderShared
   285  
   286  	// Cached values that are expected to not change
   287  	resources   []ResourceType
   288  	dataSources []DataSource
   289  
   290  	Error     error // Error is the list of errors from the shadow
   291  	ErrorLock sync.Mutex
   292  }
   293  
   294  type shadowResourceProviderShared struct {
   295  	// NOTE: Anytime a value is added here, be sure to add it to
   296  	// the Close() method so that it is closed.
   297  
   298  	CloseErr           shadow.Value
   299  	Input              shadow.Value
   300  	Validate           shadow.Value
   301  	Configure          shadow.Value
   302  	ValidateResource   shadow.KeyedValue
   303  	Apply              shadow.KeyedValue
   304  	Diff               shadow.KeyedValue
   305  	Refresh            shadow.KeyedValue
   306  	ValidateDataSource shadow.KeyedValue
   307  	ReadDataDiff       shadow.KeyedValue
   308  	ReadDataApply      shadow.KeyedValue
   309  }
   310  
   311  func (p *shadowResourceProviderShared) Close() error {
   312  	closers := []io.Closer{
   313  		&p.CloseErr, &p.Input, &p.Validate,
   314  		&p.Configure, &p.ValidateResource, &p.Apply, &p.Diff,
   315  		&p.Refresh, &p.ValidateDataSource, &p.ReadDataDiff,
   316  	}
   317  
   318  	for _, c := range closers {
   319  		// This should never happen, but we don't panic because a panic
   320  		// could affect the real behavior of Terraform and a shadow should
   321  		// never be able to do that.
   322  		if err := c.Close(); err != nil {
   323  			return err
   324  		}
   325  	}
   326  
   327  	return nil
   328  }
   329  
   330  func (p *shadowResourceProviderShadow) CloseShadow() error {
   331  	err := p.Shared.Close()
   332  	if err != nil {
   333  		err = fmt.Errorf("close error: %s", err)
   334  	}
   335  
   336  	return err
   337  }
   338  
   339  func (p *shadowResourceProviderShadow) ShadowError() error {
   340  	return p.Error
   341  }
   342  
   343  func (p *shadowResourceProviderShadow) Resources() []ResourceType {
   344  	return p.resources
   345  }
   346  
   347  func (p *shadowResourceProviderShadow) DataSources() []DataSource {
   348  	return p.dataSources
   349  }
   350  
   351  func (p *shadowResourceProviderShadow) Close() error {
   352  	v := p.Shared.CloseErr.Value()
   353  	if v == nil {
   354  		return nil
   355  	}
   356  
   357  	return v.(error)
   358  }
   359  
   360  func (p *shadowResourceProviderShadow) Input(
   361  	input UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   362  	// Get the result of the input call
   363  	raw := p.Shared.Input.Value()
   364  	if raw == nil {
   365  		return nil, nil
   366  	}
   367  
   368  	result, ok := raw.(*shadowResourceProviderInput)
   369  	if !ok {
   370  		p.ErrorLock.Lock()
   371  		defer p.ErrorLock.Unlock()
   372  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   373  			"Unknown 'input' shadow value: %#v", raw))
   374  		return nil, nil
   375  	}
   376  
   377  	// Compare the parameters, which should be identical
   378  	if !c.Equal(result.Config) {
   379  		p.ErrorLock.Lock()
   380  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   381  			"Input had unequal configurations (real, then shadow):\n\n%#v\n\n%#v",
   382  			result.Config, c))
   383  		p.ErrorLock.Unlock()
   384  	}
   385  
   386  	// Return the results
   387  	return result.Result, result.ResultErr
   388  }
   389  
   390  func (p *shadowResourceProviderShadow) Validate(c *ResourceConfig) ([]string, []error) {
   391  	// Get the result of the validate call
   392  	raw := p.Shared.Validate.Value()
   393  	if raw == nil {
   394  		return nil, nil
   395  	}
   396  
   397  	result, ok := raw.(*shadowResourceProviderValidate)
   398  	if !ok {
   399  		p.ErrorLock.Lock()
   400  		defer p.ErrorLock.Unlock()
   401  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   402  			"Unknown 'validate' shadow value: %#v", raw))
   403  		return nil, nil
   404  	}
   405  
   406  	// Compare the parameters, which should be identical
   407  	if !c.Equal(result.Config) {
   408  		p.ErrorLock.Lock()
   409  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   410  			"Validate had unequal configurations (real, then shadow):\n\n%#v\n\n%#v",
   411  			result.Config, c))
   412  		p.ErrorLock.Unlock()
   413  	}
   414  
   415  	// Return the results
   416  	return result.ResultWarn, result.ResultErr
   417  }
   418  
   419  func (p *shadowResourceProviderShadow) Configure(c *ResourceConfig) error {
   420  	// Get the result of the call
   421  	raw := p.Shared.Configure.Value()
   422  	if raw == nil {
   423  		return nil
   424  	}
   425  
   426  	result, ok := raw.(*shadowResourceProviderConfigure)
   427  	if !ok {
   428  		p.ErrorLock.Lock()
   429  		defer p.ErrorLock.Unlock()
   430  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   431  			"Unknown 'configure' shadow value: %#v", raw))
   432  		return nil
   433  	}
   434  
   435  	// Compare the parameters, which should be identical
   436  	if !c.Equal(result.Config) {
   437  		p.ErrorLock.Lock()
   438  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   439  			"Configure had unequal configurations (real, then shadow):\n\n%#v\n\n%#v",
   440  			result.Config, c))
   441  		p.ErrorLock.Unlock()
   442  	}
   443  
   444  	// Return the results
   445  	return result.Result
   446  }
   447  
   448  // Stop returns immediately.
   449  func (p *shadowResourceProviderShadow) Stop() error {
   450  	return nil
   451  }
   452  
   453  func (p *shadowResourceProviderShadow) ValidateResource(t string, c *ResourceConfig) ([]string, []error) {
   454  	// Unique key
   455  	key := t
   456  
   457  	// Get the initial value
   458  	raw := p.Shared.ValidateResource.Value(key)
   459  
   460  	// Find a validation with our configuration
   461  	var result *shadowResourceProviderValidateResource
   462  	for {
   463  		// Get the value
   464  		if raw == nil {
   465  			p.ErrorLock.Lock()
   466  			defer p.ErrorLock.Unlock()
   467  			p.Error = multierror.Append(p.Error, fmt.Errorf(
   468  				"Unknown 'ValidateResource' call for %q:\n\n%#v",
   469  				key, c))
   470  			return nil, nil
   471  		}
   472  
   473  		wrapper, ok := raw.(*shadowResourceProviderValidateResourceWrapper)
   474  		if !ok {
   475  			p.ErrorLock.Lock()
   476  			defer p.ErrorLock.Unlock()
   477  			p.Error = multierror.Append(p.Error, fmt.Errorf(
   478  				"Unknown 'ValidateResource' shadow value: %#v", raw))
   479  			return nil, nil
   480  		}
   481  
   482  		// Look for the matching call with our configuration
   483  		wrapper.RLock()
   484  		for _, call := range wrapper.Calls {
   485  			if call.Config.Equal(c) {
   486  				result = call
   487  				break
   488  			}
   489  		}
   490  		wrapper.RUnlock()
   491  
   492  		// If we found a result, exit
   493  		if result != nil {
   494  			break
   495  		}
   496  
   497  		// Wait for a change so we can get the wrapper again
   498  		raw = p.Shared.ValidateResource.WaitForChange(key)
   499  	}
   500  
   501  	return result.Warns, result.Errors
   502  }
   503  
   504  func (p *shadowResourceProviderShadow) Apply(
   505  	info *InstanceInfo,
   506  	state *InstanceState,
   507  	diff *InstanceDiff) (*InstanceState, error) {
   508  	// Unique key
   509  	key := info.uniqueId()
   510  	raw := p.Shared.Apply.Value(key)
   511  	if raw == nil {
   512  		p.ErrorLock.Lock()
   513  		defer p.ErrorLock.Unlock()
   514  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   515  			"Unknown 'apply' call for %q:\n\n%#v\n\n%#v",
   516  			key, state, diff))
   517  		return nil, nil
   518  	}
   519  
   520  	result, ok := raw.(*shadowResourceProviderApply)
   521  	if !ok {
   522  		p.ErrorLock.Lock()
   523  		defer p.ErrorLock.Unlock()
   524  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   525  			"Unknown 'apply' shadow value for %q: %#v", key, raw))
   526  		return nil, nil
   527  	}
   528  
   529  	// Compare the parameters, which should be identical
   530  	if !state.Equal(result.State) {
   531  		p.ErrorLock.Lock()
   532  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   533  			"Apply %q: state had unequal states (real, then shadow):\n\n%#v\n\n%#v",
   534  			key, result.State, state))
   535  		p.ErrorLock.Unlock()
   536  	}
   537  
   538  	if !diff.Equal(result.Diff) {
   539  		p.ErrorLock.Lock()
   540  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   541  			"Apply %q: unequal diffs (real, then shadow):\n\n%#v\n\n%#v",
   542  			key, result.Diff, diff))
   543  		p.ErrorLock.Unlock()
   544  	}
   545  
   546  	return result.Result, result.ResultErr
   547  }
   548  
   549  func (p *shadowResourceProviderShadow) Diff(
   550  	info *InstanceInfo,
   551  	state *InstanceState,
   552  	desired *ResourceConfig) (*InstanceDiff, error) {
   553  	// Unique key
   554  	key := info.uniqueId()
   555  	raw := p.Shared.Diff.Value(key)
   556  	if raw == nil {
   557  		p.ErrorLock.Lock()
   558  		defer p.ErrorLock.Unlock()
   559  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   560  			"Unknown 'diff' call for %q:\n\n%#v\n\n%#v",
   561  			key, state, desired))
   562  		return nil, nil
   563  	}
   564  
   565  	result, ok := raw.(*shadowResourceProviderDiff)
   566  	if !ok {
   567  		p.ErrorLock.Lock()
   568  		defer p.ErrorLock.Unlock()
   569  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   570  			"Unknown 'diff' shadow value: %#v", raw))
   571  		return nil, nil
   572  	}
   573  
   574  	// Compare the parameters, which should be identical
   575  	if !state.Equal(result.State) {
   576  		p.ErrorLock.Lock()
   577  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   578  			"Diff %q had unequal states (real, then shadow):\n\n%#v\n\n%#v",
   579  			key, result.State, state))
   580  		p.ErrorLock.Unlock()
   581  	}
   582  	if !desired.Equal(result.Desired) {
   583  		p.ErrorLock.Lock()
   584  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   585  			"Diff %q had unequal states (real, then shadow):\n\n%#v\n\n%#v",
   586  			key, result.Desired, desired))
   587  		p.ErrorLock.Unlock()
   588  	}
   589  
   590  	return result.Result, result.ResultErr
   591  }
   592  
   593  func (p *shadowResourceProviderShadow) Refresh(
   594  	info *InstanceInfo,
   595  	state *InstanceState) (*InstanceState, error) {
   596  	// Unique key
   597  	key := info.uniqueId()
   598  	raw := p.Shared.Refresh.Value(key)
   599  	if raw == nil {
   600  		p.ErrorLock.Lock()
   601  		defer p.ErrorLock.Unlock()
   602  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   603  			"Unknown 'refresh' call for %q:\n\n%#v",
   604  			key, state))
   605  		return nil, nil
   606  	}
   607  
   608  	result, ok := raw.(*shadowResourceProviderRefresh)
   609  	if !ok {
   610  		p.ErrorLock.Lock()
   611  		defer p.ErrorLock.Unlock()
   612  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   613  			"Unknown 'refresh' shadow value: %#v", raw))
   614  		return nil, nil
   615  	}
   616  
   617  	// Compare the parameters, which should be identical
   618  	if !state.Equal(result.State) {
   619  		p.ErrorLock.Lock()
   620  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   621  			"Refresh %q had unequal states (real, then shadow):\n\n%#v\n\n%#v",
   622  			key, result.State, state))
   623  		p.ErrorLock.Unlock()
   624  	}
   625  
   626  	return result.Result, result.ResultErr
   627  }
   628  
   629  func (p *shadowResourceProviderShadow) ValidateDataSource(
   630  	t string, c *ResourceConfig) ([]string, []error) {
   631  	// Unique key
   632  	key := t
   633  
   634  	// Get the initial value
   635  	raw := p.Shared.ValidateDataSource.Value(key)
   636  
   637  	// Find a validation with our configuration
   638  	var result *shadowResourceProviderValidateDataSource
   639  	for {
   640  		// Get the value
   641  		if raw == nil {
   642  			p.ErrorLock.Lock()
   643  			defer p.ErrorLock.Unlock()
   644  			p.Error = multierror.Append(p.Error, fmt.Errorf(
   645  				"Unknown 'ValidateDataSource' call for %q:\n\n%#v",
   646  				key, c))
   647  			return nil, nil
   648  		}
   649  
   650  		wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper)
   651  		if !ok {
   652  			p.ErrorLock.Lock()
   653  			defer p.ErrorLock.Unlock()
   654  			p.Error = multierror.Append(p.Error, fmt.Errorf(
   655  				"Unknown 'ValidateDataSource' shadow value: %#v", raw))
   656  			return nil, nil
   657  		}
   658  
   659  		// Look for the matching call with our configuration
   660  		wrapper.RLock()
   661  		for _, call := range wrapper.Calls {
   662  			if call.Config.Equal(c) {
   663  				result = call
   664  				break
   665  			}
   666  		}
   667  		wrapper.RUnlock()
   668  
   669  		// If we found a result, exit
   670  		if result != nil {
   671  			break
   672  		}
   673  
   674  		// Wait for a change so we can get the wrapper again
   675  		raw = p.Shared.ValidateDataSource.WaitForChange(key)
   676  	}
   677  
   678  	return result.Warns, result.Errors
   679  }
   680  
   681  func (p *shadowResourceProviderShadow) ReadDataDiff(
   682  	info *InstanceInfo,
   683  	desired *ResourceConfig) (*InstanceDiff, error) {
   684  	// Unique key
   685  	key := info.uniqueId()
   686  	raw := p.Shared.ReadDataDiff.Value(key)
   687  	if raw == nil {
   688  		p.ErrorLock.Lock()
   689  		defer p.ErrorLock.Unlock()
   690  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   691  			"Unknown 'ReadDataDiff' call for %q:\n\n%#v",
   692  			key, desired))
   693  		return nil, nil
   694  	}
   695  
   696  	result, ok := raw.(*shadowResourceProviderReadDataDiff)
   697  	if !ok {
   698  		p.ErrorLock.Lock()
   699  		defer p.ErrorLock.Unlock()
   700  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   701  			"Unknown 'ReadDataDiff' shadow value: %#v", raw))
   702  		return nil, nil
   703  	}
   704  
   705  	// Compare the parameters, which should be identical
   706  	if !desired.Equal(result.Desired) {
   707  		p.ErrorLock.Lock()
   708  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   709  			"ReadDataDiff %q had unequal configs (real, then shadow):\n\n%#v\n\n%#v",
   710  			key, result.Desired, desired))
   711  		p.ErrorLock.Unlock()
   712  	}
   713  
   714  	return result.Result, result.ResultErr
   715  }
   716  
   717  func (p *shadowResourceProviderShadow) ReadDataApply(
   718  	info *InstanceInfo,
   719  	d *InstanceDiff) (*InstanceState, error) {
   720  	// Unique key
   721  	key := info.uniqueId()
   722  	raw := p.Shared.ReadDataApply.Value(key)
   723  	if raw == nil {
   724  		p.ErrorLock.Lock()
   725  		defer p.ErrorLock.Unlock()
   726  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   727  			"Unknown 'ReadDataApply' call for %q:\n\n%#v",
   728  			key, d))
   729  		return nil, nil
   730  	}
   731  
   732  	result, ok := raw.(*shadowResourceProviderReadDataApply)
   733  	if !ok {
   734  		p.ErrorLock.Lock()
   735  		defer p.ErrorLock.Unlock()
   736  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   737  			"Unknown 'ReadDataApply' shadow value: %#v", raw))
   738  		return nil, nil
   739  	}
   740  
   741  	// Compare the parameters, which should be identical
   742  	if !d.Equal(result.Diff) {
   743  		p.ErrorLock.Lock()
   744  		p.Error = multierror.Append(p.Error, fmt.Errorf(
   745  			"ReadDataApply: unequal diffs (real, then shadow):\n\n%#v\n\n%#v",
   746  			result.Diff, d))
   747  		p.ErrorLock.Unlock()
   748  	}
   749  
   750  	return result.Result, result.ResultErr
   751  }
   752  
   753  func (p *shadowResourceProviderShadow) ImportState(info *InstanceInfo, id string) ([]*InstanceState, error) {
   754  	panic("import not supported by shadow graph")
   755  }
   756  
   757  // The structs for the various function calls are put below. These structs
   758  // are used to carry call information across the real/shadow boundaries.
   759  
   760  type shadowResourceProviderInput struct {
   761  	Config    *ResourceConfig
   762  	Result    *ResourceConfig
   763  	ResultErr error
   764  }
   765  
   766  type shadowResourceProviderValidate struct {
   767  	Config     *ResourceConfig
   768  	ResultWarn []string
   769  	ResultErr  []error
   770  }
   771  
   772  type shadowResourceProviderConfigure struct {
   773  	Config *ResourceConfig
   774  	Result error
   775  }
   776  
   777  type shadowResourceProviderValidateResourceWrapper struct {
   778  	sync.RWMutex
   779  
   780  	Calls []*shadowResourceProviderValidateResource
   781  }
   782  
   783  type shadowResourceProviderValidateResource struct {
   784  	Config *ResourceConfig
   785  	Warns  []string
   786  	Errors []error
   787  }
   788  
   789  type shadowResourceProviderApply struct {
   790  	State     *InstanceState
   791  	Diff      *InstanceDiff
   792  	Result    *InstanceState
   793  	ResultErr error
   794  }
   795  
   796  type shadowResourceProviderDiff struct {
   797  	State     *InstanceState
   798  	Desired   *ResourceConfig
   799  	Result    *InstanceDiff
   800  	ResultErr error
   801  }
   802  
   803  type shadowResourceProviderRefresh struct {
   804  	State     *InstanceState
   805  	Result    *InstanceState
   806  	ResultErr error
   807  }
   808  
   809  type shadowResourceProviderValidateDataSourceWrapper struct {
   810  	sync.RWMutex
   811  
   812  	Calls []*shadowResourceProviderValidateDataSource
   813  }
   814  
   815  type shadowResourceProviderValidateDataSource struct {
   816  	Config *ResourceConfig
   817  	Warns  []string
   818  	Errors []error
   819  }
   820  
   821  type shadowResourceProviderReadDataDiff struct {
   822  	Desired   *ResourceConfig
   823  	Result    *InstanceDiff
   824  	ResultErr error
   825  }
   826  
   827  type shadowResourceProviderReadDataApply struct {
   828  	Diff      *InstanceDiff
   829  	Result    *InstanceState
   830  	ResultErr error
   831  }