Skip to content

Commit

Permalink
Port provider_meta functionality from core.
Browse files Browse the repository at this point in the history
Port the functionality added in hashicorp/terraform#22583 that allows
providers to receive arbitrary, provider-definable module-scoped
information from configs.
  • Loading branch information
paddycarver committed Apr 28, 2020
1 parent ac1c092 commit d992533
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 6 deletions.
8 changes: 8 additions & 0 deletions helper/schema/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ type Provider struct {
// and must *not* implement Create, Update or Delete.
DataSourcesMap map[string]*Resource

// ProviderMetaSchema is the schema for the configuration of the meta
// information for this provider. If this provider has no meta info,
// this can be omitted. This functionality is currently experimental
// and subject to change or break without warning; it should only be
// used by providers that are collaborating on its use with the
// Terraform team.
ProviderMetaSchema map[string]*Schema

// ConfigureFunc is a function for configuring the provider. If the
// provider doesn't need to be configured, this can be omitted.
//
Expand Down
12 changes: 12 additions & 0 deletions helper/schema/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ func (r *Resource) Apply(
return s, append(diags, diag.FromErr(err))
}

if s != nil && data != nil {
data.providerMeta = s.ProviderMeta
}

// Instance Diff shoould have the timeout info, need to copy it over to the
// ResourceData meta
rt := ResourceTimeout{}
Expand Down Expand Up @@ -537,6 +541,10 @@ func (r *Resource) RefreshWithoutUpgrade(
}
data.timeouts = &rt

if s != nil {
data.providerMeta = s.ProviderMeta
}

exists, err := r.Exists(data, meta)
if err != nil {
return s, append(diags, diag.FromErr(err))
Expand All @@ -553,6 +561,10 @@ func (r *Resource) RefreshWithoutUpgrade(
}
data.timeouts = &rt

if s != nil {
data.providerMeta = s.ProviderMeta
}

diags = append(diags, r.read(ctx, data, meta)...)

state := data.State()
Expand Down
22 changes: 16 additions & 6 deletions helper/schema/resource_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"sync"
"time"

"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/go-cty/cty/gocty"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

Expand All @@ -19,12 +21,13 @@ import (
// The most relevant methods to take a look at are Get and Set.
type ResourceData struct {
// Settable (internally)
schema map[string]*Schema
config *terraform.ResourceConfig
state *terraform.InstanceState
diff *terraform.InstanceDiff
meta map[string]interface{}
timeouts *ResourceTimeout
schema map[string]*Schema
config *terraform.ResourceConfig
state *terraform.InstanceState
diff *terraform.InstanceDiff
meta map[string]interface{}
timeouts *ResourceTimeout
providerMeta cty.Value

// Don't set
multiReader *MultiLevelFieldReader
Expand Down Expand Up @@ -506,3 +509,10 @@ func (d *ResourceData) get(addr []string, source getSource) getResult {
Schema: schema,
}
}

func (d *ResourceData) GetProviderMeta(dst interface{}) error {
if d.providerMeta.IsNull() {
return nil
}
return gocty.FromCtyValue(d.providerMeta, &dst)
}
38 changes: 38 additions & 0 deletions internal/helper/plugin/grpc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ func (s *GRPCProviderServer) GetSchema(_ context.Context, req *proto.GetProvider
Block: convert.ConfigSchemaToProto(s.getProviderSchemaBlock()),
}

resp.ProviderMeta = &proto.Schema{
Block: convert.ConfigSchemaToProto(s.getProviderMetaSchemaBlock()),
}

for typ, res := range s.provider.ResourcesMap {
resp.ResourceSchemas[typ] = &proto.Schema{
Version: int64(res.SchemaVersion),
Expand All @@ -89,6 +93,10 @@ func (s *GRPCProviderServer) getProviderSchemaBlock() *configschema.Block {
return schema.InternalMap(s.provider.Schema).CoreConfigSchema()
}

func (s *GRPCProviderServer) getProviderMetaSchemaBlock() *configschema.Block {
return schema.InternalMap(s.provider.ProviderMetaSchema).CoreConfigSchema()
}

func (s *GRPCProviderServer) getResourceSchemaBlock(name string) *configschema.Block {
res := s.provider.ResourcesMap[name]
return res.CoreConfigSchema()
Expand Down Expand Up @@ -540,6 +548,16 @@ func (s *GRPCProviderServer) ReadResource(ctx context.Context, req *proto.ReadRe
}
instanceState.Meta = private

pmSchemaBlock := s.getProviderMetaSchemaBlock()
if pmSchemaBlock != nil && req.ProviderMeta != nil {
providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
instanceState.ProviderMeta = providerSchemaVal
}

newInstanceState, diags := res.RefreshWithoutUpgrade(ctx, instanceState, s.provider.Meta())
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, diags)
if diags.HasError() {
Expand Down Expand Up @@ -639,6 +657,16 @@ func (s *GRPCProviderServer) PlanResourceChange(ctx context.Context, req *proto.

priorState.Meta = priorPrivate

pmSchemaBlock := s.getProviderMetaSchemaBlock()
if pmSchemaBlock != nil && req.ProviderMeta != nil {
providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
priorState.ProviderMeta = providerSchemaVal
}

// Ensure there are no nulls that will cause helper/schema to panic.
if err := validateConfigNulls(proposedNewStateVal, nil); err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
Expand Down Expand Up @@ -900,6 +928,16 @@ func (s *GRPCProviderServer) ApplyResourceChange(ctx context.Context, req *proto
}
}

pmSchemaBlock := s.getProviderMetaSchemaBlock()
if pmSchemaBlock != nil && req.ProviderMeta != nil {
providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
priorState.ProviderMeta = providerSchemaVal
}

newInstanceState, diags := res.Apply(ctx, priorState, diff, s.provider.Meta())
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, diags)

Expand Down
2 changes: 2 additions & 0 deletions terraform/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,8 @@ type InstanceState struct {
// and collections.
Meta map[string]interface{} `json:"meta"`

ProviderMeta cty.Value

// Tainted is used to mark a resource for recreation.
Tainted bool `json:"tainted"`

Expand Down

0 comments on commit d992533

Please sign in to comment.