From 8676b59ee2b6a1e9af0b6acc9ede183ddfcd9783 Mon Sep 17 00:00:00 2001 From: Paddy Carver Date: Tue, 1 Oct 2019 12:23:05 -0700 Subject: [PATCH] Set ProviderMeta during PlanResourceChange. Set the ProviderMeta value when planning resource changes, and add a test to ensure that it's getting set properly. --- terraform/context_apply_test.go | 49 ++++++++++++++++++++++- terraform/eval_diff.go | 23 +++++++++++ terraform/node_resource_apply_instance.go | 1 + terraform/node_resource_plan.go | 2 + terraform/node_resource_plan_instance.go | 1 + 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index e4abdebd88..97bb2bc4b7 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -11314,7 +11314,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) { } } -func TestContext2Apply_ProviderMeta_set(t *testing.T) { +func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) { m := testModule(t, "provider-meta-set") p := testProvider("test") p.ApplyFn = testApplyFn @@ -11364,3 +11364,50 @@ func TestContext2Apply_ProviderMeta_set(t *testing.T) { t.Fatalf("Expected meta.Baz to be \"quux\", got %q", meta.Baz) } } + +func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[string]providers.Factory{ + "test": testProviderFuncFixed(p), + }, + ), + }) + + if _, diags := ctx.Plan(); diags.HasErrors() { + t.Fatalf("plan errors: %s", diags.Err()) + } + + if !p.PlanResourceChangeCalled { + t.Fatalf("PlanResourceChange not called") + } + if p.PlanResourceChangeRequest.ProviderMeta.IsNull() { + t.Fatalf("null ProviderMeta in PlanResourceChange") + } + type metaStruct struct { + Baz string `cty:"baz"` + } + var meta metaStruct + err := gocty.FromCtyValue(p.PlanResourceChangeRequest.ProviderMeta, &meta) + if err != nil { + t.Fatalf("Error parsing cty value: %s", err) + } + if meta.Baz != "quux" { + t.Fatalf("Expected meta.Baz to be \"quux\", got %q", meta.Baz) + } +} diff --git a/terraform/eval_diff.go b/terraform/eval_diff.go index cc9046c20b..85e96bc0fc 100644 --- a/terraform/eval_diff.go +++ b/terraform/eval_diff.go @@ -93,6 +93,7 @@ type EvalDiff struct { Config *configs.Resource Provider *providers.Interface ProviderAddr addrs.AbsProviderConfig + ProviderMeta *configs.ProviderMeta ProviderSchema **ProviderSchema State **states.ResourceInstanceObject PreviousDiff **plans.ResourceInstanceChange @@ -140,6 +141,26 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { return nil, diags.Err() } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMeta != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", (*n.Config).ProviderConfigAddr()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &n.ProviderMeta.ProviderRange, + }) + } else { + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(n.ProviderMeta.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + absAddr := n.Addr.Absolute(ctx.Path()) var priorVal cty.Value var priorValTainted cty.Value @@ -204,6 +225,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { PriorState: priorVal, ProposedNewState: proposedNewVal, PriorPrivate: priorPrivate, + ProviderMeta: metaConfigVal, }) diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config)) if diags.HasErrors() { @@ -379,6 +401,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { PriorState: nullPriorVal, ProposedNewState: proposedNewVal, PriorPrivate: plannedPrivate, + ProviderMeta: metaConfigVal, }) // We need to tread carefully here, since if there are any warnings // in here they probably also came out of our previous call to diff --git a/terraform/node_resource_apply_instance.go b/terraform/node_resource_apply_instance.go index fe4260899e..e0d4a3f9e9 100644 --- a/terraform/node_resource_apply_instance.go +++ b/terraform/node_resource_apply_instance.go @@ -287,6 +287,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe Config: n.Config, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMeta: n.ProviderMeta, ProviderSchema: &providerSchema, State: &state, PreviousDiff: &diff, diff --git a/terraform/node_resource_plan.go b/terraform/node_resource_plan.go index ec4aa9322a..7e3c7c1376 100644 --- a/terraform/node_resource_plan.go +++ b/terraform/node_resource_plan.go @@ -98,6 +98,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { a.ResolvedProvider = n.ResolvedProvider a.Schema = n.Schema a.ProvisionerSchemas = n.ProvisionerSchemas + a.ProviderMeta = n.ProviderMeta return &NodePlannableResourceInstance{ NodeAbstractResourceInstance: a, @@ -116,6 +117,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { a.ResolvedProvider = n.ResolvedProvider a.Schema = n.Schema a.ProvisionerSchemas = n.ProvisionerSchemas + a.ProviderMeta = n.ProviderMeta return &NodePlannableResourceInstanceOrphan{ NodeAbstractResourceInstance: a, diff --git a/terraform/node_resource_plan_instance.go b/terraform/node_resource_plan_instance.go index 05ccefc348..4e4fa60b00 100644 --- a/terraform/node_resource_plan_instance.go +++ b/terraform/node_resource_plan_instance.go @@ -174,6 +174,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe CreateBeforeDestroy: n.ForceCreateBeforeDestroy, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMeta: n.ProviderMeta, ProviderSchema: &providerSchema, State: &state, OutputChange: &change,