get more depends_on info for data source

Since data sources may be read during refresh or early in plan, they
need to know if there are any inherited dependencies from containing
modules too.
This commit is contained in:
James Bardin 2020-06-03 21:36:42 -04:00
parent a03c86f612
commit e74ebe1787

View File

@ -43,6 +43,12 @@ type GraphNodeAttachDependencies interface {
AttachDependencies([]addrs.ConfigResource)
}
// graphNodeDependsOn is implemented by resources that need to expose any
// references set via DependsOn in their configuration.
type graphNodeDependsOn interface {
DependsOn() []*addrs.Reference
}
// graphNodeAttachResourceDependencies records all resources that are transitively
// referenced through depends_on in the configuration. This is used by data
// resources to determine if they can be read during the plan, or if they need
@ -55,8 +61,8 @@ type GraphNodeAttachDependencies interface {
// "perpetual diff"
type graphNodeAttachResourceDependencies interface {
GraphNodeConfigResource
graphNodeDependsOn
AttachResourceDependencies([]addrs.ConfigResource)
DependsOn() []*addrs.Reference
}
// GraphNodeReferenceOutside is an interface that can optionally be implemented.
@ -122,7 +128,7 @@ func (t *ReferenceTransformer) Transform(g *Graph) error {
type depMap map[string]addrs.ConfigResource
// addDep adds the vertex if it represents a resource in the
// add stores the vertex if it represents a resource in the
// graph.
func (m depMap) add(v dag.Vertex) {
// we're only concerned with resources which may have changes that
@ -155,34 +161,32 @@ func (t attachDataResourceDependenciesTransformer) Transform(g *Graph) error {
if !ok {
continue
}
selfAddr := depender.ResourceAddr()
// Only data need to attach depends_on, so they can determine if they
// are eligible to be read during plan.
if selfAddr.Resource.Mode != addrs.DataResourceMode {
if depender.ResourceAddr().Resource.Mode != addrs.DataResourceMode {
continue
}
// depMap will only add resource references and dedupe
m := make(depMap)
for _, dep := range refMap.DependsOn(v) {
// depMap will only add resource references then dedupe
deps := make(depMap)
for _, dep := range refMap.dependsOn(g, depender) {
// any the dependency
m.add(dep)
// and check any ancestors
deps.add(dep)
// and check any ancestors for transitive dependencies
ans, _ := g.Ancestors(dep)
for _, v := range ans {
m.add(v)
deps.add(v)
}
}
deps := make([]addrs.ConfigResource, 0, len(m))
for _, d := range m {
deps = append(deps, d)
res := make([]addrs.ConfigResource, 0, len(deps))
for _, d := range deps {
res = append(res, d)
}
log.Printf("[TRACE] AttachDependsOnTransformer: %s depends on %s", depender.ResourceAddr(), deps)
depender.AttachResourceDependencies(deps)
log.Printf("[TRACE] attachDataDependenciesTransformer: %s depends on %s", depender.ResourceAddr(), res)
depender.AttachResourceDependencies(res)
}
return nil
@ -304,37 +308,64 @@ func (m ReferenceMap) References(v dag.Vertex) []dag.Vertex {
return matches
}
// DependsOn returns the set of vertices that the given vertex refers to from
// dependsOn returns the set of vertices that the given vertex refers to from
// the configured depends_on.
func (m ReferenceMap) DependsOn(v dag.Vertex) []dag.Vertex {
depender, ok := v.(graphNodeAttachResourceDependencies)
if !ok {
return nil
}
func (m ReferenceMap) dependsOn(g *Graph, depender graphNodeDependsOn) []dag.Vertex {
var matches []dag.Vertex
refs := depender.DependsOn()
for _, ref := range depender.DependsOn() {
for _, ref := range refs {
subject := ref.Subject
key := m.referenceMapKey(v, subject)
key := m.referenceMapKey(depender, subject)
vertices, ok := m[key]
if !ok {
log.Printf("[WARN] DependOn: reference not found: %q", subject)
log.Printf("[WARN] DependsOn: reference not found: %q", subject)
continue
}
for _, rv := range vertices {
// don't include self-references
if rv == v {
if rv == depender {
continue
}
matches = append(matches, rv)
}
}
matches = append(matches, m.parentModuleDependsOn(g, depender)...)
return matches
}
// parentModuleDependsOn returns the set of vertices that a data sources parent
// module references through the module call's depends_on.
func (n ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsOn) []dag.Vertex {
var res []dag.Vertex
// look for containing modules with DependsOn
for _, v := range g.DownEdges(depender) {
mod, ok := v.(*nodeExpandModule)
if !ok {
continue
}
for _, dep := range n.dependsOn(g, mod) {
// add the dependency
res = append(res, dep)
// and check any ancestors
ans, _ := g.Ancestors(dep)
for _, v := range ans {
res = append(res, v)
}
}
// recurse up through parent modules
res = append(res, n.parentModuleDependsOn(g, mod)...)
}
return res
}
func (m *ReferenceMap) mapKey(path addrs.Module, addr addrs.Referenceable) string {
return fmt.Sprintf("%s|%s", path.String(), addr.String())
}