Skip to content

Commit

Permalink
core: ResourceProvider.ReadDataDiff method
Browse files Browse the repository at this point in the history
In situations where data resource configuration is computed (and thus we
can't read data during "refresh") we will defer ReadData until the
"apply" phase, but during "plan" we still need to know which attributes
are going to become available once we read.

To achieve this using the pre-existing concepts, we represent the future
data instance state as a diff for the "creation" of the data instance.
The new provider method ReadDataDiff is responsible for producing this
diff.

Using a diff to represent this, while conceptually a little strange at
first, allows us to effectively describe which attributes exist and which
are computed, and to include this information in the plan result so that
the user can see the full dependency graph for the apply phase.
  • Loading branch information
apparentlymart committed May 8, 2016
1 parent 0c5bd0d commit ce07201
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
13 changes: 13 additions & 0 deletions helper/schema/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ func (p *Provider) ReadData(
return r.ReadData(c, p.meta)
}

// ReadDataDiff implementation of terraform.ResourceProvider interface.
func (p *Provider) ReadDataDiff(
info *terraform.InstanceInfo,
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {

r, ok := p.DataSourcesMap[info.Type]
if !ok {
return nil, fmt.Errorf("unknown data source: %s", info.Type)
}

return r.Diff(nil, c)
}

// DataSources implementation of terraform.ResourceProvider interface.
func (p *Provider) DataSources() []terraform.DataSource {
keys := make([]string, 0, len(p.DataSourcesMap))
Expand Down
41 changes: 41 additions & 0 deletions plugin/resource_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,26 @@ func (p *ResourceProvider) ReadData(
return resp.State, err
}

func (p *ResourceProvider) ReadDataDiff(
info *terraform.InstanceInfo,
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
var resp ResourceProviderReadDataDiffResponse
args := &ResourceProviderReadDataDiffArgs{
Info: info,
Config: c,
}

err := p.Client.Call("Plugin.ReadDataDiff", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}

return resp.Diff, err
}

func (p *ResourceProvider) DataSources() []terraform.DataSource {
var result []terraform.DataSource

Expand Down Expand Up @@ -311,6 +331,16 @@ type ResourceProviderReadDataResponse struct {
Error *plugin.BasicError
}

type ResourceProviderReadDataDiffArgs struct {
Info *terraform.InstanceInfo
Config *terraform.ResourceConfig
}

type ResourceProviderReadDataDiffResponse struct {
Diff *terraform.InstanceDiff
Error *plugin.BasicError
}

type ResourceProviderValidateArgs struct {
Config *terraform.ResourceConfig
}
Expand Down Expand Up @@ -460,6 +490,17 @@ func (s *ResourceProviderServer) ReadData(
return nil
}

func (s *ResourceProviderServer) ReadDataDiff(
args *ResourceProviderReadDataDiffArgs,
result *ResourceProviderReadDataDiffResponse) error {
diff, err := s.Provider.ReadDataDiff(args.Info, args.Config)
*result = ResourceProviderReadDataDiffResponse{
Diff: diff,
Error: plugin.NewBasicError(err),
}
return nil
}

func (s *ResourceProviderServer) DataSources(
nothing interface{},
result *[]terraform.DataSource) error {
Expand Down
8 changes: 8 additions & 0 deletions terraform/resource_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ type ResourceProvider interface {
// ReadData initializes a data instance, which will be of one of the
// types returned by DataSources.
ReadData(*InstanceInfo, *ResourceConfig) (*InstanceState, error)

// ReadDataDiff produces a diff that describes the result of a future
// ReadData as if it were the creation of the data resource.
// This is called when ReadData itself cannot yet be called due to
// computed interpolations within the configuration, and tells Terraform
// which attributes will become available once the data source is read,
// thus allowing dependent resources to be verified.
ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
}

// ResourceProviderCloser is an interface that providers that can close
Expand Down
22 changes: 22 additions & 0 deletions terraform/resource_provider_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ type MockResourceProvider struct {
ReadDataFn func(*InstanceInfo, *ResourceConfig) (*InstanceState, error)
ReadDataReturn *InstanceState
ReadDataReturnError error
ReadDataDiffCalled bool
ReadDataDiffInfo *InstanceInfo
ReadDataDiffDesired *ResourceConfig
ReadDataDiffFn func(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
ReadDataDiffReturn *InstanceDiff
ReadDataDiffReturnError error
DataSourcesCalled bool
DataSourcesReturn []DataSource
ValidateCalled bool
Expand Down Expand Up @@ -222,6 +228,22 @@ func (p *MockResourceProvider) ReadData(
return p.ReadDataReturn, p.ReadDataReturnError
}

func (p *MockResourceProvider) ReadDataDiff(
info *InstanceInfo,
desired *ResourceConfig) (*InstanceDiff, error) {
p.Lock()
defer p.Unlock()

p.ReadDataDiffCalled = true
p.ReadDataDiffInfo = info
p.ReadDataDiffDesired = desired
if p.ReadDataDiffFn != nil {
return p.ReadDataDiffFn(info, desired)
}

return p.ReadDataDiffReturn, p.ReadDataDiffReturnError
}

func (p *MockResourceProvider) DataSources() []DataSource {
p.Lock()
defer p.Unlock()
Expand Down

0 comments on commit ce07201

Please sign in to comment.