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 {
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
}
// GraphNodeModulePath
func (n *NodeLocal) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted
func (n *NodeLocal) RemoveIfNotTargeted() bool {
return true

View File

@ -39,6 +39,14 @@ func (n *nodeExpandModule) Path() addrs.ModuleInstance {
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
func (n *nodeExpandModule) References() []*addrs.Reference {
var refs []*addrs.Reference

View File

@ -29,6 +29,14 @@ func (n *NodeModuleRemoved) Path() addrs.ModuleInstance {
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
func (n *NodeModuleRemoved) EvalTree() EvalNode {
return &EvalOpFilter{

View File

@ -54,6 +54,11 @@ func (n *NodePlannableModuleVariable) Path() addrs.ModuleInstance {
return n.Module.UnkeyedInstanceShim()
}
// GraphNodeModulePath
func (n *NodePlannableModuleVariable) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferencer
func (n *NodePlannableModuleVariable) References() []*addrs.Reference {
@ -137,6 +142,11 @@ func (n *NodeApplyableModuleVariable) Path() addrs.ModuleInstance {
return n.Addr.Module.Parent()
}
// GraphNodeModulePath
func (n *NodeApplyableModuleVariable) ModulePath() addrs.Module {
return n.Addr.Module.Parent().Module()
}
// RemovableIfNotTargeted
func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool {
// 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()
}
// GraphNodeModulePath
func (n *NodePlannableOutput) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferenceable
func (n *NodePlannableOutput) ReferenceableAddrs() []addrs.Referenceable {
// 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
}
// GraphNodeModulePath
func (n *NodeApplyableOutput) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted
func (n *NodeApplyableOutput) RemoveIfNotTargeted() bool {
// 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()
}
// GraphNodeModulePath
func (n *NodeDestroyableOutput) ModulePath() addrs.Module {
return n.Module
}
// RemovableIfNotTargeted
func (n *NodeDestroyableOutput) RemoveIfNotTargeted() bool {
// 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
}
// GraphNodeModulePath
func (n *NodeOutputOrphan) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// GraphNodeEvalable
func (n *NodeOutputOrphan) EvalTree() EvalNode {
return &EvalOpFilter{

View File

@ -44,6 +44,11 @@ func (n *NodeAbstractProvider) Path() addrs.ModuleInstance {
return n.Addr.Module
}
// GraphNodeModulePath
func (n *NodeAbstractProvider) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// RemovableIfNotTargeted
func (n *NodeAbstractProvider) RemoveIfNotTargeted() bool {
// 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
}
// GraphNodeModulePath
func (n *NodeAbstractResource) ModulePath() addrs.Module {
return n.Addr.Module.Module()
}
// GraphNodeReferenceable
func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable {
return []addrs.Referenceable{n.Addr.Resource}

View File

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

View File

@ -22,7 +22,7 @@ import (
// be referenced and other methods of referencing may still be possible (such
// as by path!)
type GraphNodeReferenceable interface {
GraphNodeSubPath
GraphNodeModulePath
// ReferenceableAddrs returns a list of addresses through which this can be
// referenced.
@ -32,7 +32,7 @@ type GraphNodeReferenceable interface {
// GraphNodeReferencer must be implemented by nodes that reference other
// Terraform items and therefore depend on them.
type GraphNodeReferencer interface {
GraphNodeSubPath
GraphNodeModulePath
// References returns a list of references made by this node, which
// 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 {
return nil
}
if _, ok := v.(GraphNodeSubPath); !ok {
return nil
}
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
// panic if the given vertex does not implement that interface.
func (m *ReferenceMap) vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstance {
sp, ok := v.(GraphNodeSubPath)
func vertexReferenceablePath(v dag.Vertex) addrs.ModuleInstance {
sp, ok := v.(GraphNodeModulePath)
if !ok {
// 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 {
@ -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.
return sp.Path()
return sp.ModulePath().UnkeyedInstanceShim()
}
// 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
// will panic if the given vertex does not implement that interface.
func vertexReferencePath(referrer dag.Vertex) addrs.ModuleInstance {
sp, ok := referrer.(GraphNodeSubPath)
func vertexReferencePath(v dag.Vertex) addrs.ModuleInstance {
sp, ok := v.(GraphNodeModulePath)
if !ok {
// 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
// it was declared.
_, 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
// was declared.
return sp.Path()
return sp.ModulePath().UnkeyedInstanceShim()
}
// referenceMapKey produces keys for the "edges" map. "referrer" is the vertex
@ -374,7 +371,7 @@ func NewReferenceMap(vs []dag.Vertex) *ReferenceMap {
continue
}
path := m.vertexReferenceablePath(v)
path := vertexReferenceablePath(v)
// Go through and cache them
for _, addr := range rn.ReferenceableAddrs() {

View File

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