Merge pull request #26458 from hashicorp/jbardin/data-ref-index

data sources with indexed references to managed resources
This commit is contained in:
James Bardin 2020-10-02 13:27:28 -04:00 committed by GitHub
commit 32681190ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 29 deletions

View File

@ -6346,17 +6346,28 @@ func TestContext2Plan_dataReferencesResource(t *testing.T) {
m := testModuleInline(t, map[string]string{ m := testModuleInline(t, map[string]string{
"main.tf": ` "main.tf": `
locals { locals {
x = "value" x = "value"
} }
resource "test_resource" "a" { resource "test_resource" "a" {
value = local.x value = local.x
} }
// test_resource.a.value can be resolved during plan, but the reference implies // test_resource.a.value can be resolved during plan, but the reference implies
// that the data source should wait until the resource is created. // that the data source should wait until the resource is created.
data "test_data_source" "d" { data "test_data_source" "d" {
foo = test_resource.a.value foo = test_resource.a.value
}
// ensure referencing an indexed instance that has not yet created will also
// delay reading the data source
resource "test_resource" "b" {
count = 2
value = local.x
}
data "test_data_source" "e" {
foo = test_resource.b[0].value
} }
`}) `})

View File

@ -328,30 +328,8 @@ func (m ReferenceMap) dependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Ve
refs := depender.DependsOn() refs := depender.DependsOn()
// For data sources we implicitly treat references as depends_on entries. // get any implied dependencies for data sources
// If a data source references a resource, even if that reference is refs = append(refs, m.dataDependsOn(depender)...)
// resolvable, it stands to reason that the user intends for the data
// source to require that resource in some way.
if n, ok := depender.(GraphNodeConfigResource); ok &&
n.ResourceAddr().Resource.Mode == addrs.DataResourceMode {
for _, r := range depender.References() {
// We don't need to wait on referenced data sources. They have no
// side effects, so our configuration reference should suffice for
// proper ordering.
var resAddr addrs.Resource
switch s := r.Subject.(type) {
case addrs.Resource:
resAddr = s
case addrs.ResourceInstance:
resAddr = s.Resource
}
if resAddr.Mode == addrs.ManagedResourceMode {
refs = append(refs, r)
}
}
}
// This is where we record that a module has depends_on configured. // This is where we record that a module has depends_on configured.
if _, ok := depender.(*nodeExpandModule); ok && len(refs) > 0 { if _, ok := depender.(*nodeExpandModule); ok && len(refs) > 0 {
@ -391,10 +369,44 @@ func (m ReferenceMap) dependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Ve
return res, fromModule || fromParentModule return res, fromModule || fromParentModule
} }
// Return extra depends_on references if this is a data source.
// For data sources we implicitly treat references to managed resources as
// depends_on entries. If a data source references a managed resource, even if
// that reference is resolvable, it stands to reason that the user intends for
// the data source to require that resource in some way.
func (m ReferenceMap) dataDependsOn(depender graphNodeDependsOn) []*addrs.Reference {
var refs []*addrs.Reference
if n, ok := depender.(GraphNodeConfigResource); ok &&
n.ResourceAddr().Resource.Mode == addrs.DataResourceMode {
for _, r := range depender.References() {
var resAddr addrs.Resource
switch s := r.Subject.(type) {
case addrs.Resource:
resAddr = s
case addrs.ResourceInstance:
resAddr = s.Resource
r.Subject = resAddr
}
if resAddr.Mode != addrs.ManagedResourceMode {
// We only want to wait on directly referenced managed resources.
// Data sources have no external side effects, so normal
// references to them in the config will suffice for proper
// ordering.
continue
}
refs = append(refs, r)
}
}
return refs
}
// parentModuleDependsOn returns the set of vertices that a data sources parent // parentModuleDependsOn returns the set of vertices that a data sources parent
// module references through the module call's depends_on. The bool return // module references through the module call's depends_on. The bool return
// value indicates if depends_on was found in a parent module configuration. // value indicates if depends_on was found in a parent module configuration.
func (n ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) { func (m ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) {
var res []dag.Vertex var res []dag.Vertex
fromModule := false fromModule := false
@ -408,7 +420,7 @@ func (n ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsO
continue continue
} }
deps, fromParentModule := n.dependsOn(g, mod) deps, fromParentModule := m.dependsOn(g, mod)
for _, dep := range deps { for _, dep := range deps {
// add the dependency // add the dependency
res = append(res, dep) res = append(res, dep)