github.com/ves/terraform@v0.8.0-beta2/terraform/shadow_resource_provider.go (about)

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