From 877348c031100d682f5f18f3a49cffac4bc4a1f3 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 19 Apr 2021 12:35:10 -0400 Subject: [PATCH] wrong operation during destroy plan walk The destroy plan walk was identifying itself as a normal plan, and causing providers to be configured when they were not needed. Since the provider configuration may not be complete during the minimal destroy plan walk, validation or configuration may fail. --- terraform/context.go | 2 +- terraform/context_plan2_test.go | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/terraform/context.go b/terraform/context.go index ca15073ba..3809061ab 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -633,7 +633,7 @@ func (c *Context) destroyPlan() (*plans.Plan, tfdiags.Diagnostics) { } // Do the walk - walker, walkDiags := c.walk(graph, walkPlan) + walker, walkDiags := c.walk(graph, walkPlanDestroy) diags = diags.Append(walker.NonFatalDiagnostics) diags = diags.Append(walkDiags) if walkDiags.HasErrors() { diff --git a/terraform/context_plan2_test.go b/terraform/context_plan2_test.go index 0444a775c..f95f7f6e3 100644 --- a/terraform/context_plan2_test.go +++ b/terraform/context_plan2_test.go @@ -439,3 +439,49 @@ output "result" { } } } + +func TestContext2Plan_destroyNoProviderConfig(t *testing.T) { + // providers do not need to be configured during a destroy plan + p := simpleMockProvider() + p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { + v := req.Config.GetAttr("test_string") + if v.IsNull() || !v.IsKnown() || v.AsString() != "ok" { + resp.Diagnostics = resp.Diagnostics.Append(errors.New("invalid provider configuration")) + } + return resp + } + + m := testModuleInline(t, map[string]string{ + "main.tf": ` +locals { + value = "ok" +} + +provider "test" { + test_string = local.value +} +`, + }) + + addr := mustResourceInstanceAddr("test_object.a") + state := states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ + AttrsJSON: []byte(`{"test_string":"foo"}`), + Status: states.ObjectReady, + }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) + }) + + ctx := testContext2(t, &ContextOpts{ + Config: m, + State: state, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + Destroy: true, + }) + + _, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatal(diags.Err()) + } +}