diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index 06f9a7baf..fb7c26487 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -6414,3 +6414,61 @@ resource "test_instance" "a" { t.Fatal("Resource should not have been refreshed") } } + +func TestContext2Plan_dataInModuleDependsOn(t *testing.T) { + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + readDataSourceB := false + p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { + cfg := req.Config.AsValueMap() + foo := cfg["foo"].AsString() + + cfg["id"] = cty.StringVal("ID") + cfg["foo"] = cty.StringVal("new") + + if foo == "b" { + readDataSourceB = true + } + + resp.State = cty.ObjectVal(cfg) + return resp + } + + m := testModuleInline(t, map[string]string{ + "main.tf": ` +module "a" { + source = "./mod_a" +} + +module "b" { + source = "./mod_b" + depends_on = [module.a] +}`, + "mod_a/main.tf": ` +data "test_data_source" "a" { + foo = "a" +}`, + "mod_b/main.tf": ` +data "test_data_source" "b" { + foo = "b" +}`, + }) + + ctx := testContext2(t, &ContextOpts{ + Config: m, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + // The change to data source a should not prevent data source b from being + // read. + if !readDataSourceB { + t.Fatal("data source b was not read during plan") + } +} diff --git a/terraform/eval_read_data_plan.go b/terraform/eval_read_data_plan.go index f88575129..226594299 100644 --- a/terraform/eval_read_data_plan.go +++ b/terraform/eval_read_data_plan.go @@ -7,6 +7,7 @@ import ( "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/plans" "github.com/hashicorp/terraform/plans/objchange" "github.com/hashicorp/terraform/states" @@ -154,6 +155,14 @@ func (n *evalReadDataPlan) forcePlanRead(ctx EvalContext) bool { // configuration. changes := ctx.Changes() for _, d := range n.dependsOn { + if d.Resource.Mode == addrs.DataResourceMode { + // Data sources have no external side effects, so they pose a need + // to delay this read. If they do have a change planned, it must be + // because of a dependency on a managed resource, in which case + // we'll also encounter it in this list of dependencies. + continue + } + for _, change := range changes.GetChangesForConfigResource(d) { if change != nil && change.Action != plans.NoOp { return true