Merge pull request #24331 from hashicorp/jbardin/module-expansion-in-part

More module expansion groundwork
This commit is contained in:
James Bardin 2020-03-11 11:10:02 -04:00 committed by GitHub
commit 856791ec7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 324 additions and 347 deletions

View File

@ -40,6 +40,10 @@ func (m Module) String() string {
return strings.Join(steps, ".")
}
func (m Module) Equal(other Module) bool {
return m.String() == other.String()
}
// Child returns the address of a child call in the receiver, identified by the
// given name.
func (m Module) Child(name string) Module {
@ -77,3 +81,17 @@ func (m Module) Call() (Module, ModuleCall) {
Name: callName,
}
}
// Ancestors returns a slice containing the receiver and all of its ancestor
// modules, all the way up to (and including) the root module. The result is
// ordered by depth, with the root module always first.
//
// Since the result always includes the root module, a caller may choose to
// ignore it by slicing the result with [1:].
func (m Module) Ancestors() []Module {
ret := make([]Module, 0, len(m)+1)
for i := 0; i <= len(m); i++ {
ret = append(ret, m[:i])
}
return ret
}

View File

@ -52,9 +52,9 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
// vertexCtx is the context that we use when evaluating. This
// is normally the context of our graph but can be overridden
// with a GraphNodeSubPath impl.
// with a GraphNodeModuleInstance impl.
vertexCtx := ctx
if pn, ok := v.(GraphNodeSubPath); ok && len(pn.Path()) > 0 {
if pn, ok := v.(GraphNodeModuleInstance); ok && len(pn.Path()) > 0 {
vertexCtx = walker.EnterPath(pn.Path())
defer walker.ExitPath(pn.Path())
}
@ -101,19 +101,6 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
log.Printf("[TRACE] vertex %q: produced no dynamic subgraph", dag.VertexName(v))
}
}
// If the node has a subgraph, then walk the subgraph
if sn, ok := v.(GraphNodeSubgraph); ok {
log.Printf("[TRACE] vertex %q: entering static subgraph", dag.VertexName(v))
subDiags := sn.Subgraph().(*Graph).walk(walker)
if subDiags.HasErrors() {
log.Printf("[TRACE] vertex %q: static subgraph encountered errors", dag.VertexName(v))
return
}
log.Printf("[TRACE] vertex %q: static subgraph completed successfully", dag.VertexName(v))
}
return
}

View File

@ -209,7 +209,7 @@ func TestApplyGraphBuilder_doubleCBD(t *testing.T) {
continue
}
switch tv.Addr.Resource.Name {
switch tv.Addr.Name {
case "A":
destroyA = fmt.Sprintf("test_object.A (destroy deposed %s)", tv.DeposedKey)
case "B":

View File

@ -4,8 +4,14 @@ import (
"github.com/hashicorp/terraform/addrs"
)
// GraphNodeSubPath says that a node is part of a graph with a
// GraphNodeModuleInstance says that a node is part of a graph with a
// different path, and the context should be adjusted accordingly.
type GraphNodeSubPath interface {
type GraphNodeModuleInstance 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

@ -15,7 +15,7 @@ type NodeRefreshableDataResource struct {
}
var (
_ GraphNodeSubPath = (*NodeRefreshableDataResource)(nil)
_ GraphNodeModuleInstance = (*NodeRefreshableDataResource)(nil)
_ GraphNodeDynamicExpandable = (*NodeRefreshableDataResource)(nil)
_ GraphNodeReferenceable = (*NodeRefreshableDataResource)(nil)
_ GraphNodeReferencer = (*NodeRefreshableDataResource)(nil)

View File

@ -40,11 +40,12 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleOut(t *testing.T) {
n := &NodeRefreshableDataResource{
NodeAbstractResource: &NodeAbstractResource{
Addr: addrs.RootModuleInstance.Resource(
addrs.DataResourceMode,
"aws_instance",
"foo",
),
Addr: addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: addrs.RootModule,
Config: m.Module.DataResources["data.aws_instance.foo"],
},
}
@ -124,11 +125,12 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleIn(t *testing.T) {
n := &NodeRefreshableDataResource{
NodeAbstractResource: &NodeAbstractResource{
Addr: addrs.RootModuleInstance.Resource(
addrs.DataResourceMode,
"aws_instance",
"foo",
),
Addr: addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: addrs.RootModule,
Config: m.Module.DataResources["data.aws_instance.foo"],
ResolvedProvider: addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("aws"),

View File

@ -1,12 +1,73 @@
package terraform
import (
"log"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/dag"
"github.com/hashicorp/terraform/lang"
)
// NodePlannableLocal represents a named local value in a configuration module,
// which has not yet been expanded.
type NodePlannableLocal struct {
Addr addrs.LocalValue
Module addrs.Module
Config *configs.Local
}
var (
_ RemovableIfNotTargeted = (*NodePlannableLocal)(nil)
_ GraphNodeReferenceable = (*NodePlannableLocal)(nil)
_ GraphNodeReferencer = (*NodePlannableLocal)(nil)
_ GraphNodeDynamicExpandable = (*NodePlannableLocal)(nil)
)
func (n *NodePlannableLocal) Name() string {
path := n.Module.String()
addr := n.Addr.String()
if path != "" {
return path + "." + addr
}
return addr
}
// GraphNodeModulePath
func (n *NodePlannableLocal) ModulePath() addrs.Module {
return n.Module
}
// RemovableIfNotTargeted
func (n *NodePlannableLocal) RemoveIfNotTargeted() bool {
return true
}
// GraphNodeReferenceable
func (n *NodePlannableLocal) ReferenceableAddrs() []addrs.Referenceable {
return []addrs.Referenceable{n.Addr}
}
// GraphNodeReferencer
func (n *NodePlannableLocal) References() []*addrs.Reference {
refs, _ := lang.ReferencesInExpr(n.Config.Expr)
return appendResourceDestroyReferences(refs)
}
func (n *NodePlannableLocal) DynamicExpand(ctx EvalContext) (*Graph, error) {
var g Graph
expander := ctx.InstanceExpander()
for _, module := range expander.ExpandModule(n.Module) {
o := &NodeLocal{
Addr: n.Addr.Absolute(module),
Config: n.Config,
}
log.Printf("[TRACE] Expanding local: adding %s as %T", o.Addr.String(), o)
g.Add(o)
}
return &g, nil
}
// NodeLocal represents a named local value in a particular module.
//
// Local value nodes only have one operation, common to all walk types:
@ -17,23 +78,28 @@ type NodeLocal struct {
}
var (
_ GraphNodeSubPath = (*NodeLocal)(nil)
_ RemovableIfNotTargeted = (*NodeLocal)(nil)
_ GraphNodeReferenceable = (*NodeLocal)(nil)
_ GraphNodeReferencer = (*NodeLocal)(nil)
_ GraphNodeEvalable = (*NodeLocal)(nil)
_ dag.GraphNodeDotter = (*NodeLocal)(nil)
_ GraphNodeModuleInstance = (*NodeLocal)(nil)
_ RemovableIfNotTargeted = (*NodeLocal)(nil)
_ GraphNodeReferenceable = (*NodeLocal)(nil)
_ GraphNodeReferencer = (*NodeLocal)(nil)
_ GraphNodeEvalable = (*NodeLocal)(nil)
_ dag.GraphNodeDotter = (*NodeLocal)(nil)
)
func (n *NodeLocal) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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

@ -1,8 +1,6 @@
package terraform
import (
"log"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/lang"
@ -13,30 +11,27 @@ import (
// might expand into multiple module instances depending on how it is
// configured.
type nodeExpandModule struct {
CallerAddr addrs.ModuleInstance
Addr addrs.Module
Call addrs.ModuleCall
Config *configs.Module
ModuleCall *configs.ModuleCall
}
var (
_ GraphNodeSubPath = (*nodeExpandModule)(nil)
_ RemovableIfNotTargeted = (*nodeExpandModule)(nil)
_ GraphNodeEvalable = (*nodeExpandModule)(nil)
_ GraphNodeReferencer = (*nodeExpandModule)(nil)
)
func (n *nodeExpandModule) Name() string {
return n.CallerAddr.Child(n.Call.Name, addrs.NoKey).String()
return n.Addr.String()
}
// GraphNodeSubPath implementation
func (n *nodeExpandModule) Path() addrs.ModuleInstance {
// 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.CallerAddr
return n.Addr.Parent()
}
// GraphNodeReferencer implementation
@ -77,8 +72,7 @@ func (n *nodeExpandModule) RemoveIfNotTargeted() bool {
// GraphNodeEvalable
func (n *nodeExpandModule) EvalTree() EvalNode {
return &evalPrepareModuleExpansion{
CallerAddr: n.CallerAddr,
Call: n.Call,
Addr: n.Addr,
Config: n.Config,
ModuleCall: n.ModuleCall,
}
@ -87,8 +81,7 @@ func (n *nodeExpandModule) EvalTree() EvalNode {
// evalPrepareModuleExpansion is an EvalNode implementation
// that sets the count or for_each on the instance expander
type evalPrepareModuleExpansion struct {
CallerAddr addrs.ModuleInstance
Call addrs.ModuleCall
Addr addrs.Module
Config *configs.Module
ModuleCall *configs.ModuleCall
}
@ -97,12 +90,7 @@ func (n *evalPrepareModuleExpansion) Eval(ctx EvalContext) (interface{}, error)
eachMode := states.NoEach
expander := ctx.InstanceExpander()
if n.ModuleCall == nil {
// FIXME: should we have gotten here with no module call?
log.Printf("[TRACE] evalPrepareModuleExpansion: %s is a singleton", n.CallerAddr.Child(n.Call.Name, addrs.NoKey))
expander.SetModuleSingle(n.CallerAddr, n.Call)
return nil, nil
}
_, call := n.Addr.Call()
count, countDiags := evaluateResourceCountExpression(n.ModuleCall.Count, ctx)
if countDiags.HasErrors() {
@ -122,13 +110,18 @@ func (n *evalPrepareModuleExpansion) Eval(ctx EvalContext) (interface{}, error)
eachMode = states.EachMap
}
switch eachMode {
case states.EachList:
expander.SetModuleCount(ctx.Path(), n.Call, count)
case states.EachMap:
expander.SetModuleForEach(ctx.Path(), n.Call, forEach)
default:
expander.SetModuleSingle(n.CallerAddr, n.Call)
// nodeExpandModule itself does not have visibility into how it's ancestors
// were expended, so we use the expander here to provide all possible paths
// to our module, and register module instances with each of them.
for _, path := range expander.ExpandModule(n.Addr.Parent()) {
switch eachMode {
case states.EachList:
expander.SetModuleCount(path, call, count)
case states.EachMap:
expander.SetModuleForEach(path, call, forEach)
default:
expander.SetModuleSingle(path, call)
}
}
return nil, nil

View File

@ -13,7 +13,7 @@ type NodeModuleRemoved struct {
}
var (
_ GraphNodeSubPath = (*NodeModuleRemoved)(nil)
_ GraphNodeModuleInstance = (*NodeModuleRemoved)(nil)
_ RemovableIfNotTargeted = (*NodeModuleRemoved)(nil)
_ GraphNodeEvalable = (*NodeModuleRemoved)(nil)
_ GraphNodeReferencer = (*NodeModuleRemoved)(nil)
@ -24,11 +24,19 @@ func (n *NodeModuleRemoved) Name() string {
return fmt.Sprintf("%s (removed)", n.Addr.String())
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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

@ -25,14 +25,13 @@ var (
_ GraphNodeReferenceOutside = (*NodePlannableModuleVariable)(nil)
_ GraphNodeReferenceable = (*NodePlannableModuleVariable)(nil)
_ GraphNodeReferencer = (*NodePlannableModuleVariable)(nil)
_ GraphNodeSubPath = (*NodePlannableModuleVariable)(nil)
_ RemovableIfNotTargeted = (*NodePlannableModuleVariable)(nil)
)
func (n *NodePlannableModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
var g Graph
expander := ctx.InstanceExpander()
for _, module := range expander.ExpandModule(ctx.Path().Module()) {
for _, module := range expander.ExpandModule(n.Module) {
o := &NodeApplyableModuleVariable{
Addr: n.Addr.Absolute(module),
Config: n.Config,
@ -47,11 +46,9 @@ func (n *NodePlannableModuleVariable) Name() string {
return fmt.Sprintf("%s.%s", n.Module, n.Addr.String())
}
// GraphNodeSubPath
func (n *NodePlannableModuleVariable) Path() addrs.ModuleInstance {
// Return an UnkeyedInstanceShim as our placeholder,
// given that modules will be unexpanded at this point in the walk
return n.Module.UnkeyedInstanceShim()
// GraphNodeModulePath
func (n *NodePlannableModuleVariable) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferencer
@ -117,7 +114,7 @@ type NodeApplyableModuleVariable struct {
// Ensure that we are implementing all of the interfaces we think we are
// implementing.
var (
_ GraphNodeSubPath = (*NodeApplyableModuleVariable)(nil)
_ GraphNodeModuleInstance = (*NodeApplyableModuleVariable)(nil)
_ RemovableIfNotTargeted = (*NodeApplyableModuleVariable)(nil)
_ GraphNodeReferenceOutside = (*NodeApplyableModuleVariable)(nil)
_ GraphNodeReferenceable = (*NodeApplyableModuleVariable)(nil)
@ -130,13 +127,18 @@ func (n *NodeApplyableModuleVariable) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
func (n *NodeApplyableModuleVariable) Path() addrs.ModuleInstance {
// We execute in the parent scope (above our own module) because
// expressions in our value are resolved in that context.
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

@ -2,6 +2,7 @@ package terraform
import (
"fmt"
"log"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
@ -18,10 +19,8 @@ type NodePlannableOutput struct {
}
var (
_ GraphNodeSubPath = (*NodePlannableOutput)(nil)
_ RemovableIfNotTargeted = (*NodePlannableOutput)(nil)
_ GraphNodeReferenceable = (*NodePlannableOutput)(nil)
//_ GraphNodeEvalable = (*NodePlannableOutput)(nil)
_ RemovableIfNotTargeted = (*NodePlannableOutput)(nil)
_ GraphNodeReferenceable = (*NodePlannableOutput)(nil)
_ GraphNodeReferencer = (*NodePlannableOutput)(nil)
_ GraphNodeDynamicExpandable = (*NodePlannableOutput)(nil)
)
@ -29,26 +28,29 @@ var (
func (n *NodePlannableOutput) DynamicExpand(ctx EvalContext) (*Graph, error) {
var g Graph
expander := ctx.InstanceExpander()
for _, module := range expander.ExpandModule(ctx.Path().Module()) {
for _, module := range expander.ExpandModule(n.Module) {
o := &NodeApplyableOutput{
Addr: n.Addr.Absolute(module),
Config: n.Config,
}
// log.Printf("[TRACE] Expanding output: adding %s as %T", o.Addr.String(), o)
log.Printf("[TRACE] Expanding output: adding %s as %T", o.Addr.String(), o)
g.Add(o)
}
return &g, nil
}
func (n *NodePlannableOutput) Name() string {
return n.Addr.Absolute(n.Module.UnkeyedInstanceShim()).String()
path := n.Module.String()
addr := n.Addr.String()
if path != "" {
return path + "." + addr
}
return addr
}
// GraphNodeSubPath
func (n *NodePlannableOutput) Path() addrs.ModuleInstance {
// Return an UnkeyedInstanceShim as our placeholder,
// given that modules will be unexpanded at this point in the walk
return n.Module.UnkeyedInstanceShim()
// GraphNodeModulePath
func (n *NodePlannableOutput) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferenceable
@ -61,9 +63,6 @@ func (n *NodePlannableOutput) ReferenceableAddrs() []addrs.Referenceable {
// the output is referenced through the module call, and via the
// module itself.
_, call := n.Module.Call()
// FIXME: make something like ModuleCallOutput for this type of reference
// that doesn't need an instance shim
callOutput := addrs.ModuleCallOutput{
Call: call.Instance(addrs.NoKey),
Name: n.Addr.Name,
@ -109,7 +108,7 @@ type NodeApplyableOutput struct {
}
var (
_ GraphNodeSubPath = (*NodeApplyableOutput)(nil)
_ GraphNodeModuleInstance = (*NodeApplyableOutput)(nil)
_ RemovableIfNotTargeted = (*NodeApplyableOutput)(nil)
_ GraphNodeTargetDownstream = (*NodeApplyableOutput)(nil)
_ GraphNodeReferenceable = (*NodeApplyableOutput)(nil)
@ -123,11 +122,16 @@ func (n *NodeApplyableOutput) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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
@ -237,7 +241,6 @@ type NodeDestroyableOutput struct {
}
var (
_ GraphNodeSubPath = (*NodeDestroyableOutput)(nil)
_ RemovableIfNotTargeted = (*NodeDestroyableOutput)(nil)
_ GraphNodeTargetDownstream = (*NodeDestroyableOutput)(nil)
_ GraphNodeReferencer = (*NodeDestroyableOutput)(nil)
@ -249,9 +252,9 @@ func (n *NodeDestroyableOutput) Name() string {
return fmt.Sprintf("%s (destroy)", n.Addr.String())
}
// GraphNodeSubPath
func (n *NodeDestroyableOutput) Path() addrs.ModuleInstance {
return n.Module.UnkeyedInstanceShim()
// GraphNodeModulePath
func (n *NodeDestroyableOutput) ModulePath() addrs.Module {
return n.Module
}
// RemovableIfNotTargeted

View File

@ -12,7 +12,7 @@ type NodeOutputOrphan struct {
}
var (
_ GraphNodeSubPath = (*NodeOutputOrphan)(nil)
_ GraphNodeModuleInstance = (*NodeOutputOrphan)(nil)
_ GraphNodeReferenceable = (*NodeOutputOrphan)(nil)
_ GraphNodeReferenceOutside = (*NodeOutputOrphan)(nil)
_ GraphNodeEvalable = (*NodeOutputOrphan)(nil)
@ -32,11 +32,16 @@ func (n *NodeOutputOrphan) ReferenceableAddrs() []addrs.Referenceable {
return referenceableAddrsForOutput(n.Addr)
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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

@ -26,7 +26,7 @@ type NodeAbstractProvider struct {
}
var (
_ GraphNodeSubPath = (*NodeAbstractProvider)(nil)
_ GraphNodeModuleInstance = (*NodeAbstractProvider)(nil)
_ RemovableIfNotTargeted = (*NodeAbstractProvider)(nil)
_ GraphNodeReferencer = (*NodeAbstractProvider)(nil)
_ GraphNodeProvider = (*NodeAbstractProvider)(nil)
@ -39,11 +39,16 @@ func (n *NodeAbstractProvider) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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

@ -14,7 +14,7 @@ type NodeDisabledProvider struct {
}
var (
_ GraphNodeSubPath = (*NodeDisabledProvider)(nil)
_ GraphNodeModuleInstance = (*NodeDisabledProvider)(nil)
_ RemovableIfNotTargeted = (*NodeDisabledProvider)(nil)
_ GraphNodeReferencer = (*NodeDisabledProvider)(nil)
_ GraphNodeProvider = (*NodeDisabledProvider)(nil)

View File

@ -14,9 +14,9 @@ type NodeProvisioner struct {
}
var (
_ GraphNodeSubPath = (*NodeProvisioner)(nil)
_ GraphNodeProvisioner = (*NodeProvisioner)(nil)
_ GraphNodeEvalable = (*NodeProvisioner)(nil)
_ GraphNodeModuleInstance = (*NodeProvisioner)(nil)
_ GraphNodeProvisioner = (*NodeProvisioner)(nil)
_ GraphNodeEvalable = (*NodeProvisioner)(nil)
)
func (n *NodeProvisioner) Name() string {
@ -28,7 +28,7 @@ func (n *NodeProvisioner) Name() string {
return result
}
// GraphNodeSubPath
// GraphNodeModuleInstance
func (n *NodeProvisioner) Path() addrs.ModuleInstance {
return n.PathValue
}

View File

@ -43,11 +43,8 @@ type GraphNodeResourceInstance interface {
// operations. It registers all the interfaces for a resource that common
// across multiple operation types.
type NodeAbstractResource struct {
//FIXME: AbstractResources are no longer absolute, because modules are not expanded.
// Addr addrs.Resource
// Module addrs.Module
Addr addrs.AbsResource // Addr is the address for this resource
Addr addrs.Resource
Module addrs.Module
// The fields below will be automatically set using the Attach
// interfaces if you're running those transforms, but also be explicitly
@ -69,7 +66,6 @@ type NodeAbstractResource struct {
}
var (
_ GraphNodeSubPath = (*NodeAbstractResource)(nil)
_ GraphNodeReferenceable = (*NodeAbstractResource)(nil)
_ GraphNodeReferencer = (*NodeAbstractResource)(nil)
_ GraphNodeProviderConsumer = (*NodeAbstractResource)(nil)
@ -83,11 +79,16 @@ var (
_ dag.GraphNodeDotter = (*NodeAbstractResource)(nil)
)
func (n *NodeAbstractResource) addr() addrs.AbsResource {
return n.Addr.Absolute(n.Module.UnkeyedInstanceShim())
}
// NewNodeAbstractResource creates an abstract resource graph node for
// the given absolute resource address.
func NewNodeAbstractResource(addr addrs.AbsResource) *NodeAbstractResource {
return &NodeAbstractResource{
Addr: addr,
Addr: addr.Resource,
Module: addr.Module.Module(),
}
}
@ -108,7 +109,7 @@ type NodeAbstractResourceInstance struct {
}
var (
_ GraphNodeSubPath = (*NodeAbstractResourceInstance)(nil)
_ GraphNodeModuleInstance = (*NodeAbstractResourceInstance)(nil)
_ GraphNodeReferenceable = (*NodeAbstractResourceInstance)(nil)
_ GraphNodeReferencer = (*NodeAbstractResourceInstance)(nil)
_ GraphNodeProviderConsumer = (*NodeAbstractResourceInstance)(nil)
@ -134,7 +135,8 @@ func NewNodeAbstractResourceInstance(addr addrs.AbsResourceInstance) *NodeAbstra
// request.
return &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
Addr: addr.ContainingResource(),
Addr: addr.Resource.Resource,
Module: addr.Module.Module(),
},
InstanceKey: addr.Resource.Key,
}
@ -148,14 +150,19 @@ func (n *NodeAbstractResourceInstance) Name() string {
return n.ResourceInstanceAddr().String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
func (n *NodeAbstractResource) Path() addrs.ModuleInstance {
return n.Addr.Module
return n.Module.UnkeyedInstanceShim()
}
// GraphNodeModulePath
func (n *NodeAbstractResource) ModulePath() addrs.Module {
return n.Module
}
// GraphNodeReferenceable
func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable {
return []addrs.Referenceable{n.Addr.Resource}
return []addrs.Referenceable{n.Addr}
}
// GraphNodeReferenceable
@ -301,7 +308,7 @@ func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
// GraphNodeProviderConsumer
func (n *NodeAbstractResource) ImpliedProvider() addrs.Provider {
return n.Addr.Resource.DefaultProvider()
return n.Addr.DefaultProvider()
}
// GraphNodeProviderConsumer
@ -329,7 +336,7 @@ func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.ProviderConfig, bool)
// GraphNodeProviderConsumer
func (n *NodeAbstractResourceInstance) ImpliedProvider() addrs.Provider {
return n.Addr.Resource.DefaultProvider()
return n.Addr.DefaultProvider()
}
// GraphNodeProvisionerConsumer
@ -359,17 +366,17 @@ func (n *NodeAbstractResource) AttachProvisionerSchema(name string, schema *conf
// GraphNodeResource
func (n *NodeAbstractResource) ResourceAddr() addrs.AbsResource {
return n.Addr
return n.addr()
}
// GraphNodeResourceInstance
func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance {
return n.NodeAbstractResource.Addr.Instance(n.InstanceKey)
return n.NodeAbstractResource.addr().Instance(n.InstanceKey)
}
// GraphNodeAddressable, TODO: remove, used by target, should unify
func (n *NodeAbstractResource) ResourceAddress() *ResourceAddress {
return NewLegacyResourceAddress(n.Addr)
return NewLegacyResourceAddress(n.addr())
}
// GraphNodeTargetable

View File

@ -19,7 +19,7 @@ type NodePlannableResource struct {
}
var (
_ GraphNodeSubPath = (*NodePlannableResource)(nil)
_ GraphNodeModuleInstance = (*NodePlannableResource)(nil)
_ GraphNodeDestroyerCBD = (*NodePlannableResource)(nil)
_ GraphNodeDynamicExpandable = (*NodePlannableResource)(nil)
_ GraphNodeReferenceable = (*NodePlannableResource)(nil)

View File

@ -17,7 +17,7 @@ type NodePlanDestroyableResourceInstance struct {
}
var (
_ GraphNodeSubPath = (*NodePlanDestroyableResourceInstance)(nil)
_ GraphNodeModuleInstance = (*NodePlanDestroyableResourceInstance)(nil)
_ GraphNodeReferenceable = (*NodePlanDestroyableResourceInstance)(nil)
_ GraphNodeReferencer = (*NodePlanDestroyableResourceInstance)(nil)
_ GraphNodeDestroyer = (*NodePlanDestroyableResourceInstance)(nil)

View File

@ -20,7 +20,7 @@ type NodePlannableResourceInstance struct {
}
var (
_ GraphNodeSubPath = (*NodePlannableResourceInstance)(nil)
_ GraphNodeModuleInstance = (*NodePlannableResourceInstance)(nil)
_ GraphNodeReferenceable = (*NodePlannableResourceInstance)(nil)
_ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil)
_ GraphNodeResource = (*NodePlannableResourceInstance)(nil)

View File

@ -13,7 +13,7 @@ type NodePlannableResourceInstanceOrphan struct {
}
var (
_ GraphNodeSubPath = (*NodePlannableResourceInstanceOrphan)(nil)
_ GraphNodeModuleInstance = (*NodePlannableResourceInstanceOrphan)(nil)
_ GraphNodeReferenceable = (*NodePlannableResourceInstanceOrphan)(nil)
_ GraphNodeReferencer = (*NodePlannableResourceInstanceOrphan)(nil)
_ GraphNodeResource = (*NodePlannableResourceInstanceOrphan)(nil)

View File

@ -25,7 +25,7 @@ type NodeRefreshableManagedResource struct {
}
var (
_ GraphNodeSubPath = (*NodeRefreshableManagedResource)(nil)
_ GraphNodeModuleInstance = (*NodeRefreshableManagedResource)(nil)
_ GraphNodeDynamicExpandable = (*NodeRefreshableManagedResource)(nil)
_ GraphNodeReferenceable = (*NodeRefreshableManagedResource)(nil)
_ GraphNodeReferencer = (*NodeRefreshableManagedResource)(nil)
@ -142,7 +142,7 @@ type NodeRefreshableManagedResourceInstance struct {
}
var (
_ GraphNodeSubPath = (*NodeRefreshableManagedResourceInstance)(nil)
_ GraphNodeModuleInstance = (*NodeRefreshableManagedResourceInstance)(nil)
_ GraphNodeReferenceable = (*NodeRefreshableManagedResourceInstance)(nil)
_ GraphNodeReferencer = (*NodeRefreshableManagedResourceInstance)(nil)
_ GraphNodeDestroyer = (*NodeRefreshableManagedResourceInstance)(nil)

View File

@ -42,9 +42,12 @@ func TestNodeRefreshableManagedResourceDynamicExpand_scaleOut(t *testing.T) {
n := &NodeRefreshableManagedResource{
NodeAbstractResource: &NodeAbstractResource{
Addr: addrs.RootModuleInstance.Resource(
addrs.ManagedResourceMode, "aws_instance", "foo",
),
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: addrs.RootModule,
Config: m.Module.ManagedResources["aws_instance.foo"],
},
}
@ -124,9 +127,12 @@ func TestNodeRefreshableManagedResourceDynamicExpand_scaleIn(t *testing.T) {
n := &NodeRefreshableManagedResource{
NodeAbstractResource: &NodeAbstractResource{
Addr: addrs.RootModuleInstance.Resource(
addrs.ManagedResourceMode, "aws_instance", "foo",
),
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: addrs.RootModule,
Config: m.Module.ManagedResources["aws_instance.foo"],
},
}
@ -166,9 +172,12 @@ func TestNodeRefreshableManagedResourceEvalTree_scaleOut(t *testing.T) {
n := &NodeRefreshableManagedResourceInstance{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
Addr: addrs.RootModuleInstance.Resource(
addrs.ManagedResourceMode, "aws_instance", "foo",
),
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: addrs.RootModule,
Config: m.Module.ManagedResources["aws_instance.foo"],
},
InstanceKey: addrs.IntKey(2),

View File

@ -15,7 +15,7 @@ type NodeValidatableResource struct {
}
var (
_ GraphNodeSubPath = (*NodeValidatableResource)(nil)
_ GraphNodeModuleInstance = (*NodeValidatableResource)(nil)
_ GraphNodeEvalable = (*NodeValidatableResource)(nil)
_ GraphNodeReferenceable = (*NodeValidatableResource)(nil)
_ GraphNodeReferencer = (*NodeValidatableResource)(nil)

View File

@ -13,20 +13,24 @@ type NodeRootVariable struct {
}
var (
_ GraphNodeSubPath = (*NodeRootVariable)(nil)
_ GraphNodeReferenceable = (*NodeRootVariable)(nil)
_ dag.GraphNodeDotter = (*NodeApplyableModuleVariable)(nil)
_ GraphNodeModuleInstance = (*NodeRootVariable)(nil)
_ GraphNodeReferenceable = (*NodeRootVariable)(nil)
_ dag.GraphNodeDotter = (*NodeApplyableModuleVariable)(nil)
)
func (n *NodeRootVariable) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
// GraphNodeModuleInstance
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

@ -9,7 +9,7 @@ import (
// that want provider configurations attached.
type GraphNodeAttachProvider interface {
// Must be implemented to determine the path for the configuration
GraphNodeSubPath
GraphNodeModuleInstance
// ProviderName with no module prefix. Example: "aws".
ProviderAddr() addrs.AbsProviderConfig

View File

@ -37,6 +37,11 @@ type ConfigTransformer struct {
uniqueMap map[string]struct{}
}
// FIXME: should we have an addr.Module + addr.Resource type?
type configName interface {
Name() string
}
func (t *ConfigTransformer) Transform(g *Graph) error {
// Lock since we use some internal state
t.l.Lock()
@ -53,8 +58,8 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
defer func() { t.uniqueMap = nil }()
if t.Unique {
for _, v := range g.Vertices() {
if rn, ok := v.(GraphNodeResource); ok {
t.uniqueMap[rn.ResourceAddr().String()] = struct{}{}
if rn, ok := v.(configName); ok {
t.uniqueMap[rn.Name()] = struct{}{}
}
}
}
@ -89,14 +94,6 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
module := config.Module
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
// For now we assume that each module call produces only one module
// instance with no key, since we don't yet support "count" and "for_each"
// on modules.
// FIXME: As part of supporting "count" and "for_each" on modules, rework
// this so that we'll "expand" the module call first and then create graph
// nodes for each module instance separately.
instPath := path.UnkeyedInstanceShim()
allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources))
for _, r := range module.ManagedResources {
allResources = append(allResources, r)
@ -113,14 +110,17 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
continue
}
addr := relAddr.Absolute(instPath)
if _, ok := t.uniqueMap[addr.String()]; ok {
abstract := &NodeAbstractResource{
Addr: relAddr,
Module: path,
}
if _, ok := t.uniqueMap[abstract.Name()]; ok {
// We've already seen a resource with this address. This should
// never happen, because we enforce uniqueness in the config loader.
continue
}
abstract := &NodeAbstractResource{Addr: addr}
var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)

View File

@ -1,18 +1,5 @@
package terraform
import (
"log"
"github.com/hashicorp/terraform/dag"
)
// GraphNodeExapndable is an interface that nodes can implement to
// signal that they can be expanded. Expanded nodes turn into
// GraphNodeSubgraph nodes within the graph.
type GraphNodeExpandable interface {
Expand(GraphBuilder) (GraphNodeSubgraph, error)
}
// GraphNodeDynamicExpandable is an interface that nodes can implement
// to signal that they can be expanded at eval-time (hence dynamic).
// These nodes are given the eval context and are expected to return
@ -20,29 +7,3 @@ type GraphNodeExpandable interface {
type GraphNodeDynamicExpandable interface {
DynamicExpand(EvalContext) (*Graph, error)
}
// GraphNodeSubgraph is an interface a node can implement if it has
// a larger subgraph that should be walked.
type GraphNodeSubgraph interface {
Subgraph() dag.Grapher
}
// ExpandTransform is a transformer that does a subgraph expansion
// at graph transform time (vs. at eval time). The benefit of earlier
// subgraph expansion is that errors with the graph build can be detected
// at an earlier stage.
type ExpandTransform struct {
Builder GraphBuilder
}
func (t *ExpandTransform) Transform(v dag.Vertex) (dag.Vertex, error) {
ev, ok := v.(GraphNodeExpandable)
if !ok {
// This isn't an expandable vertex, so just ignore it.
return v, nil
}
// Expand the subgraph!
log.Printf("[DEBUG] vertex %q: static expanding", dag.VertexName(ev))
return ev.Expand(t.Builder)
}

View File

@ -1,77 +0,0 @@
package terraform
import (
"strings"
"testing"
"github.com/hashicorp/terraform/dag"
)
func TestExpandTransform_impl(t *testing.T) {
var _ GraphVertexTransformer = new(ExpandTransform)
}
func TestExpandTransform(t *testing.T) {
var g Graph
g.Add(1)
g.Add(2)
g.Connect(dag.BasicEdge(1, 2))
tf := &ExpandTransform{}
out, err := tf.Transform(&testExpandable{
Result: &g,
})
if err != nil {
t.Fatalf("err: %s", err)
}
sn, ok := out.(GraphNodeSubgraph)
if !ok {
t.Fatalf("not subgraph: %#v", out)
}
actual := strings.TrimSpace(sn.Subgraph().(*Graph).String())
expected := strings.TrimSpace(testExpandTransformStr)
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestExpandTransform_nonExpandable(t *testing.T) {
tf := &ExpandTransform{}
out, err := tf.Transform(42)
if err != nil {
t.Fatalf("err: %s", err)
}
if out != 42 {
t.Fatalf("bad: %#v", out)
}
}
type testExpandable struct {
// Inputs
Result *Graph
ResultError error
// Outputs
Builder GraphBuilder
}
func (n *testExpandable) Expand(b GraphBuilder) (GraphNodeSubgraph, error) {
n.Builder = b
return &testSubgraph{n.Result}, n.ResultError
}
type testSubgraph struct {
Graph *Graph
}
func (n *testSubgraph) Subgraph() dag.Grapher {
return n.Graph
}
const testExpandTransformStr = `
1
2
2
`

View File

@ -48,7 +48,7 @@ type graphNodeImportState struct {
}
var (
_ GraphNodeSubPath = (*graphNodeImportState)(nil)
_ GraphNodeModuleInstance = (*graphNodeImportState)(nil)
_ GraphNodeEvalable = (*graphNodeImportState)(nil)
_ GraphNodeProviderConsumer = (*graphNodeImportState)(nil)
_ GraphNodeDynamicExpandable = (*graphNodeImportState)(nil)
@ -83,7 +83,7 @@ func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
n.ResolvedProvider = addr
}
// GraphNodeSubPath
// GraphNodeModuleInstance
func (n *graphNodeImportState) Path() addrs.ModuleInstance {
return n.Addr.Module
}
@ -199,8 +199,8 @@ type graphNodeImportStateSub struct {
}
var (
_ GraphNodeSubPath = (*graphNodeImportStateSub)(nil)
_ GraphNodeEvalable = (*graphNodeImportStateSub)(nil)
_ GraphNodeModuleInstance = (*graphNodeImportStateSub)(nil)
_ GraphNodeEvalable = (*graphNodeImportStateSub)(nil)
)
func (n *graphNodeImportStateSub) Name() string {

View File

@ -1,6 +1,7 @@
package terraform
import (
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
)
@ -20,18 +21,11 @@ func (t *LocalTransformer) transformModule(g *Graph, c *configs.Config) error {
return nil
}
// Our addressing system distinguishes between modules and module instances,
// but we're not yet ready to make that distinction here (since we don't
// support "count"/"for_each" on modules) and so we just do a naive
// transform of the module path into a module instance path, assuming that
// no keys are in use. This should be removed when "count" and "for_each"
// are implemented for modules.
path := c.Path.UnkeyedInstanceShim()
for _, local := range c.Module.Locals {
addr := path.LocalValue(local.Name)
node := &NodeLocal{
addr := addrs.LocalValue{Name: local.Name}
node := &NodePlannableLocal{
Addr: addr,
Module: c.Path,
Config: local,
}
g.Add(node)

View File

@ -33,25 +33,16 @@ func (t *ModuleExpansionTransformer) Transform(g *Graph) error {
}
func (t *ModuleExpansionTransformer) transform(g *Graph, c *configs.Config, parentNode dag.Vertex) error {
// FIXME: We're using addrs.ModuleInstance to represent the paths here
// because the rest of Terraform Core is expecting that, but in practice
// thus is representing a path through the static module instances (not
// expanded yet), and so as we weave in support for repetition of module
// calls we'll need to make the plan processing actually use addrs.Module
// to represent that our graph nodes are actually representing unexpanded
// static configuration objects, not instances.
fullAddr := c.Path.UnkeyedInstanceShim()
callerAddr, callAddr := fullAddr.Call()
_, call := c.Path.Call()
modCall := c.Parent.Module.ModuleCalls[call.Name]
modulecall := c.Parent.Module.ModuleCalls["child"]
v := &nodeExpandModule{
CallerAddr: callerAddr,
Call: callAddr,
Addr: c.Path,
Config: c.Module,
ModuleCall: modulecall,
ModuleCall: modCall,
}
g.Add(v)
log.Printf("[TRACE] ModuleExpansionTransformer: Added %s as %T", fullAddr, v)
log.Printf("[TRACE] ModuleExpansionTransformer: Added %s as %T", c.Path, v)
if parentNode != nil {
log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(v), dag.VertexName(parentNode))
@ -65,12 +56,12 @@ func (t *ModuleExpansionTransformer) transform(g *Graph, c *configs.Config, pare
// work to properly support "count" and "for_each" for modules. Nodes
// in the plan graph actually belong to modules, not to module instances.
for _, childV := range g.Vertices() {
pather, ok := childV.(GraphNodeSubPath)
pather, ok := childV.(GraphNodeModulePath)
if !ok {
continue
}
if pather.Path().Equal(fullAddr) {
log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(childV), fullAddr)
if pather.ModulePath().Equal(c.Path) {
log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(childV), c.Path)
g.Connect(dag.BasicEdge(childV, v))
}
}

View File

@ -58,15 +58,7 @@ func (t *ModuleVariableTransformer) transform(g *Graph, parent, c *configs.Confi
}
func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs.Config) error {
// Our addressing system distinguishes between modules and module instances,
// but we're not yet ready to make that distinction here (since we don't
// support "count"/"for_each" on modules) and so we just do a naive
// transform of the module path into a module instance path, assuming that
// no keys are in use. This should be removed when "count" and "for_each"
// are implemented for modules.
path := c.Path.UnkeyedInstanceShim()
_, call := path.Call()
_, call := c.Path.Call()
// Find the call in the parent module configuration, so we can get the
// expressions given for each input variable at the call site.
@ -74,7 +66,7 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs
if !exists {
// This should never happen, since it indicates an improperly-constructed
// configuration tree.
panic(fmt.Errorf("no module call block found for %s", path))
panic(fmt.Errorf("no module call block found for %s", c.Path))
}
// We need to construct a schema for the expected call arguments based on

View File

@ -72,6 +72,11 @@ func (t *DestroyOutputTransformer) Transform(g *Graph) error {
continue
}
// We only destroy root outputs
if !output.Module.Equal(addrs.RootModule) {
continue
}
// create the destroy node for this output
node := &NodeDestroyableOutput{
Addr: output.Addr,

View File

@ -44,7 +44,7 @@ func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, c
//
// Name returns the full name of the provider in the config.
type GraphNodeProvider interface {
GraphNodeSubPath
GraphNodeModuleInstance
ProviderAddr() addrs.AbsProviderConfig
Name() string
}
@ -53,7 +53,7 @@ type GraphNodeProvider interface {
// provider must implement. The CloseProviderName returned is the name of
// the provider they satisfy.
type GraphNodeCloseProvider interface {
GraphNodeSubPath
GraphNodeModuleInstance
CloseProviderAddr() addrs.AbsProviderConfig
}
@ -63,7 +63,7 @@ type GraphNodeCloseProvider interface {
// or in an ancestor module, with the resulting absolute address passed to
// SetProvider.
type GraphNodeProviderConsumer interface {
GraphNodeSubPath
GraphNodeModuleInstance
// ProvidedBy returns the address of the provider configuration the node
// refers to, if available. The following value types may be returned:
//
@ -186,7 +186,7 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
p := req.Addr
target := m[key]
_, ok := v.(GraphNodeSubPath)
_, ok := v.(GraphNodeModuleInstance)
if !ok && target == nil {
// No target and no path to traverse up from
diags = diags.Append(fmt.Errorf("%s: provider %s couldn't be found", dag.VertexName(v), p))
@ -412,7 +412,7 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
// ParentProviderTransformer connects provider nodes to their parents.
//
// This works by finding nodes that are both GraphNodeProviders and
// GraphNodeSubPath. It then connects the providers to their parent
// GraphNodeModuleInstance. It then connects the providers to their parent
// path. The parent provider is always at the root level.
type ParentProviderTransformer struct{}
@ -511,7 +511,7 @@ func (n *graphNodeCloseProvider) Name() string {
return n.Addr.String() + " (close)"
}
// GraphNodeSubPath impl.
// GraphNodeModuleInstance impl.
func (n *graphNodeCloseProvider) Path() addrs.ModuleInstance {
return n.Addr.Module
}

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
@ -288,7 +285,7 @@ func (m *ReferenceMap) References(v dag.Vertex) []dag.Vertex {
return matches
}
func (m *ReferenceMap) mapKey(path addrs.ModuleInstance, addr addrs.Referenceable) string {
func (m *ReferenceMap) mapKey(path addrs.Module, addr addrs.Referenceable) string {
return fmt.Sprintf("%s|%s", path.String(), addr.String())
}
@ -296,48 +293,48 @@ func (m *ReferenceMap) mapKey(path addrs.ModuleInstance, addr addrs.Referenceabl
// referenced. This is the path that its results from ReferenceableAddrs
// are considered to be relative to.
//
// Only GraphNodeSubPath implementations can be referenced, so this method will
// Only GraphNodeModulePath 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.Module {
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 {
// Vertex is referenced from a different module than where it was
// declared.
path, _ := outside.ReferenceOutside()
return path.UnkeyedInstanceShim()
return path
}
// Vertex is referenced from the same module as where it was declared.
return sp.Path()
return sp.ModulePath()
}
// vertexReferencePath returns the path in which references _from_ the given
// vertex must be interpreted.
//
// Only GraphNodeSubPath implementations can have references, so this method
// Only GraphNodeModulePath 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.Module {
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()
return path.UnkeyedInstanceShim()
return path
}
// Vertex makes references to objects in the same module as where it
// was declared.
return sp.Path()
return sp.ModulePath()
}
// referenceMapKey produces keys for the "edges" map. "referrer" is the vertex
@ -347,7 +344,7 @@ func vertexReferencePath(referrer dag.Vertex) addrs.ModuleInstance {
// The result is an opaque string that includes both the address of the given
// object and the address of the module instance that object belongs to.
//
// Only GraphNodeSubPath implementations can be referrers, so this method will
// Only GraphNodeModulePath implementations can be referrers, so this method will
// panic if the given vertex does not implement that interface.
func (m *ReferenceMap) referenceMapKey(referrer dag.Vertex, addr addrs.Referenceable) string {
path := vertexReferencePath(referrer)
@ -362,19 +359,13 @@ func NewReferenceMap(vs []dag.Vertex) *ReferenceMap {
// Build the lookup table
vertices := make(map[string][]dag.Vertex)
for _, v := range vs {
_, ok := v.(GraphNodeSubPath)
if !ok {
// Only nodes with paths can participate in a reference map.
continue
}
// We're only looking for referenceable nodes
rn, ok := v.(GraphNodeReferenceable)
if !ok {
continue
}
path := m.vertexReferenceablePath(v)
path := vertexReferenceablePath(v)
// Go through and cache them
for _, addr := range rn.ReferenceableAddrs() {
@ -389,11 +380,8 @@ func NewReferenceMap(vs []dag.Vertex) *ReferenceMap {
// an instance key) or as the bare module call itself (the "module"
// block in the parent module that created the instance).
callPath, call := addr.Call()
callInstPath, callInst := addr.CallInstance()
callKey := m.mapKey(callPath, call)
callInstKey := m.mapKey(callInstPath, callInst)
vertices[callKey] = append(vertices[callKey], v)
vertices[callInstKey] = append(vertices[callInstKey], v)
}
}

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