implement GraphNodeModulePath

GraphNodeModulePath is similar to GraphNodeSubPath, except that it
returns an addrs.Module rather than an addrs.ModuleInstance. This is
used by the ReferenceTransformer to connect references, when modules may
not yet be expanded.

Because references only exist within the scope of a module, we can
connect everything knowing only the module path. If the reference is to
an expanded module instance output, we can still properly order the
reference because we'll wait for the entire module to complete
evaluation.
This commit is contained in:
James Bardin 2020-03-04 21:00:16 -05:00
parent 51bdcbb48c
commit 521bdcc241
12 changed files with 91 additions and 15 deletions

View File

@ -9,3 +9,9 @@ import (
type GraphNodeSubPath interface { type GraphNodeSubPath interface {
Path() addrs.ModuleInstance Path() addrs.ModuleInstance
} }
// GraphNodeModulePath is implemented by all referenceable nodes, to indicate
// their configuration path in unexpanded modules.
type GraphNodeModulePath interface {
ModulePath() addrs.Module
}

View File

@ -34,6 +34,11 @@ func (n *NodeLocal) Path() addrs.ModuleInstance {
return n.Addr.Module return n.Addr.Module
} }
// GraphNodeModulePath
func (n *NodeLocal) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted // RemovableIfNotTargeted
func (n *NodeLocal) RemoveIfNotTargeted() bool { func (n *NodeLocal) RemoveIfNotTargeted() bool {
return true return true

View File

@ -39,6 +39,14 @@ func (n *nodeExpandModule) Path() addrs.ModuleInstance {
return n.CallerAddr return n.CallerAddr
} }
// GraphNodeModulePath implementation
func (n *nodeExpandModule) ModulePath() addrs.Module {
// This node represents the module call within a module,
// so return the CallerAddr as the path as the module
// call may expand into multiple child instances
return n.Addr
}
// GraphNodeReferencer implementation // GraphNodeReferencer implementation
func (n *nodeExpandModule) References() []*addrs.Reference { func (n *nodeExpandModule) References() []*addrs.Reference {
var refs []*addrs.Reference var refs []*addrs.Reference

View File

@ -29,6 +29,14 @@ func (n *NodeModuleRemoved) Path() addrs.ModuleInstance {
return n.Addr return n.Addr
} }
// GraphNodeModulePath implementation
func (n *NodeModuleRemoved) ModulePath() addrs.Module {
// This node represents the module call within a module,
// so return the CallerAddr as the path as the module
// call may expand into multiple child instances
return n.Addr.Module()
}
// GraphNodeEvalable // GraphNodeEvalable
func (n *NodeModuleRemoved) EvalTree() EvalNode { func (n *NodeModuleRemoved) EvalTree() EvalNode {
return &EvalOpFilter{ return &EvalOpFilter{

View File

@ -54,6 +54,11 @@ func (n *NodePlannableModuleVariable) Path() addrs.ModuleInstance {
return n.Module.UnkeyedInstanceShim() return n.Module.UnkeyedInstanceShim()
} }
// GraphNodeModulePath
func (n *NodePlannableModuleVariable) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferencer // GraphNodeReferencer
func (n *NodePlannableModuleVariable) References() []*addrs.Reference { func (n *NodePlannableModuleVariable) References() []*addrs.Reference {
@ -137,6 +142,11 @@ func (n *NodeApplyableModuleVariable) Path() addrs.ModuleInstance {
return n.Addr.Module.Parent() return n.Addr.Module.Parent()
} }
// GraphNodeModulePath
func (n *NodeApplyableModuleVariable) ModulePath() addrs.Module {
return n.Addr.Module.Parent().Module()
}
// RemovableIfNotTargeted // RemovableIfNotTargeted
func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool { func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if // We need to add this so that this node will be removed if

View File

@ -51,6 +51,11 @@ func (n *NodePlannableOutput) Path() addrs.ModuleInstance {
return n.Module.UnkeyedInstanceShim() return n.Module.UnkeyedInstanceShim()
} }
// GraphNodeModulePath
func (n *NodePlannableOutput) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferenceable // GraphNodeReferenceable
func (n *NodePlannableOutput) ReferenceableAddrs() []addrs.Referenceable { func (n *NodePlannableOutput) ReferenceableAddrs() []addrs.Referenceable {
// An output in the root module can't be referenced at all. // An output in the root module can't be referenced at all.
@ -128,6 +133,11 @@ func (n *NodeApplyableOutput) Path() addrs.ModuleInstance {
return n.Addr.Module return n.Addr.Module
} }
// GraphNodeModulePath
func (n *NodeApplyableOutput) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted // RemovableIfNotTargeted
func (n *NodeApplyableOutput) RemoveIfNotTargeted() bool { func (n *NodeApplyableOutput) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if // We need to add this so that this node will be removed if
@ -254,6 +264,11 @@ func (n *NodeDestroyableOutput) Path() addrs.ModuleInstance {
return n.Module.UnkeyedInstanceShim() return n.Module.UnkeyedInstanceShim()
} }
// GraphNodeModulePath
func (n *NodeDestroyableOutput) ModulePath() addrs.Module {
return n.Module
}
// RemovableIfNotTargeted // RemovableIfNotTargeted
func (n *NodeDestroyableOutput) RemoveIfNotTargeted() bool { func (n *NodeDestroyableOutput) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if // We need to add this so that this node will be removed if

View File

@ -37,6 +37,11 @@ func (n *NodeOutputOrphan) Path() addrs.ModuleInstance {
return n.Addr.Module return n.Addr.Module
} }
// GraphNodeModulePath
func (n *NodeOutputOrphan) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// GraphNodeEvalable // GraphNodeEvalable
func (n *NodeOutputOrphan) EvalTree() EvalNode { func (n *NodeOutputOrphan) EvalTree() EvalNode {
return &EvalOpFilter{ return &EvalOpFilter{

View File

@ -44,6 +44,11 @@ func (n *NodeAbstractProvider) Path() addrs.ModuleInstance {
return n.Addr.Module return n.Addr.Module
} }
// GraphNodeModulePath
func (n *NodeAbstractProvider) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted // RemovableIfNotTargeted
func (n *NodeAbstractProvider) RemoveIfNotTargeted() bool { func (n *NodeAbstractProvider) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if // We need to add this so that this node will be removed if

View File

@ -153,6 +153,11 @@ func (n *NodeAbstractResource) Path() addrs.ModuleInstance {
return n.Addr.Module return n.Addr.Module
} }
// GraphNodeModulePath
func (n *NodeAbstractResource) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// GraphNodeReferenceable // GraphNodeReferenceable
func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable { func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable {
return []addrs.Referenceable{n.Addr.Resource} return []addrs.Referenceable{n.Addr.Resource}

View File

@ -27,6 +27,10 @@ func (n *NodeRootVariable) Path() addrs.ModuleInstance {
return addrs.RootModuleInstance return addrs.RootModuleInstance
} }
func (n *NodeRootVariable) ModulePath() addrs.Module {
return addrs.RootModule
}
// GraphNodeReferenceable // GraphNodeReferenceable
func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable { func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable {
return []addrs.Referenceable{n.Addr} return []addrs.Referenceable{n.Addr}

View File

@ -22,7 +22,7 @@ import (
// be referenced and other methods of referencing may still be possible (such // be referenced and other methods of referencing may still be possible (such
// as by path!) // as by path!)
type GraphNodeReferenceable interface { type GraphNodeReferenceable interface {
GraphNodeSubPath GraphNodeModulePath
// ReferenceableAddrs returns a list of addresses through which this can be // ReferenceableAddrs returns a list of addresses through which this can be
// referenced. // referenced.
@ -32,7 +32,7 @@ type GraphNodeReferenceable interface {
// GraphNodeReferencer must be implemented by nodes that reference other // GraphNodeReferencer must be implemented by nodes that reference other
// Terraform items and therefore depend on them. // Terraform items and therefore depend on them.
type GraphNodeReferencer interface { type GraphNodeReferencer interface {
GraphNodeSubPath GraphNodeModulePath
// References returns a list of references made by this node, which // References returns a list of references made by this node, which
// include both a referenced address and source location information for // include both a referenced address and source location information for
@ -252,9 +252,6 @@ func (m *ReferenceMap) References(v dag.Vertex) []dag.Vertex {
if !ok { if !ok {
return nil return nil
} }
if _, ok := v.(GraphNodeSubPath); !ok {
return nil
}
var matches []dag.Vertex var matches []dag.Vertex
@ -298,11 +295,11 @@ func (m *ReferenceMap) mapKey(path addrs.ModuleInstance, addr addrs.Referenceabl
// //
// Only GraphNodeSubPath implementations can be referenced, so this method will // Only GraphNodeSubPath implementations can be referenced, so this method will
// panic if the given vertex does not implement that interface. // panic if the given vertex does not implement that interface.
func (m *ReferenceMap) vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstance { func vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstance {
sp, ok := v.(GraphNodeSubPath) sp, ok := v.(GraphNodeModulePath)
if !ok { if !ok {
// Only nodes with paths can participate in a reference map. // Only nodes with paths can participate in a reference map.
panic(fmt.Errorf("vertexMapKey on vertex type %T which doesn't implement GraphNodeSubPath", sp)) panic(fmt.Errorf("vertexMapKey on vertex type %T which doesn't implement GraphNodeModulePath", sp))
} }
if outside, ok := v.(GraphNodeReferenceOutside); ok { if outside, ok := v.(GraphNodeReferenceOutside); ok {
@ -313,7 +310,7 @@ func (m *ReferenceMap) vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstanc
} }
// Vertex is referenced from the same module as where it was declared. // Vertex is referenced from the same module as where it was declared.
return sp.Path() return sp.ModulePath().UnkeyedInstanceShim()
} }
// vertexReferencePath returns the path in which references _from_ the given // vertexReferencePath returns the path in which references _from_ the given
@ -321,14 +318,14 @@ func (m *ReferenceMap) vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstanc
// //
// Only GraphNodeSubPath implementations can have references, so this method // Only GraphNodeSubPath implementations can have references, so this method
// will panic if the given vertex does not implement that interface. // will panic if the given vertex does not implement that interface.
func vertexReferencePath(referrer dag.Vertex) addrs.ModuleInstance { func vertexReferencePath(v dag.Vertex) addrs.ModuleInstance {
sp, ok := referrer.(GraphNodeSubPath) sp, ok := v.(GraphNodeModulePath)
if !ok { if !ok {
// Only nodes with paths can participate in a reference map. // Only nodes with paths can participate in a reference map.
panic(fmt.Errorf("vertexReferencePath on vertex type %T which doesn't implement GraphNodeSubPath", sp)) panic(fmt.Errorf("vertexReferencePath on vertex type %T which doesn't implement GraphNodeModulePath", v))
} }
if outside, ok := referrer.(GraphNodeReferenceOutside); ok { if outside, ok := v.(GraphNodeReferenceOutside); ok {
// Vertex makes references to objects in a different module than where // Vertex makes references to objects in a different module than where
// it was declared. // it was declared.
_, path := outside.ReferenceOutside() _, path := outside.ReferenceOutside()
@ -337,7 +334,7 @@ func vertexReferencePath(referrer dag.Vertex) addrs.ModuleInstance {
// Vertex makes references to objects in the same module as where it // Vertex makes references to objects in the same module as where it
// was declared. // was declared.
return sp.Path() return sp.ModulePath().UnkeyedInstanceShim()
} }
// referenceMapKey produces keys for the "edges" map. "referrer" is the vertex // referenceMapKey produces keys for the "edges" map. "referrer" is the vertex
@ -374,7 +371,7 @@ func NewReferenceMap(vs []dag.Vertex) *ReferenceMap {
continue continue
} }
path := m.vertexReferenceablePath(v) path := vertexReferenceablePath(v)
// Go through and cache them // Go through and cache them
for _, addr := range rn.ReferenceableAddrs() { for _, addr := range rn.ReferenceableAddrs() {

View File

@ -153,6 +153,10 @@ func (n *graphNodeRefParentTest) Path() addrs.ModuleInstance {
return normalizeModulePath(n.PathValue) return normalizeModulePath(n.PathValue)
} }
func (n *graphNodeRefParentTest) ModulePath() addrs.Module {
return normalizeModulePath(n.PathValue).Module()
}
type graphNodeRefChildTest struct { type graphNodeRefChildTest struct {
NameValue string NameValue string
PathValue []string PathValue []string
@ -179,6 +183,10 @@ func (n *graphNodeRefChildTest) Path() addrs.ModuleInstance {
return normalizeModulePath(n.PathValue) return normalizeModulePath(n.PathValue)
} }
func (n *graphNodeRefChildTest) ModulePath() addrs.Module {
return normalizeModulePath(n.PathValue).Module()
}
const testTransformRefBasicStr = ` const testTransformRefBasicStr = `
A A
B B