mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #24331 from hashicorp/jbardin/module-expansion-in-part
More module expansion groundwork
This commit is contained in:
commit
856791ec7e
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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":
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ type NodeRefreshableDataResource struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodeRefreshableDataResource)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodeRefreshableDataResource)(nil)
|
||||
_ GraphNodeDynamicExpandable = (*NodeRefreshableDataResource)(nil)
|
||||
_ GraphNodeReferenceable = (*NodeRefreshableDataResource)(nil)
|
||||
_ GraphNodeReferencer = (*NodeRefreshableDataResource)(nil)
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
@ -14,7 +14,7 @@ type NodeDisabledProvider struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodeDisabledProvider)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodeDisabledProvider)(nil)
|
||||
_ RemovableIfNotTargeted = (*NodeDisabledProvider)(nil)
|
||||
_ GraphNodeReferencer = (*NodeDisabledProvider)(nil)
|
||||
_ GraphNodeProvider = (*NodeDisabledProvider)(nil)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -19,7 +19,7 @@ type NodePlannableResource struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodePlannableResource)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodePlannableResource)(nil)
|
||||
_ GraphNodeDestroyerCBD = (*NodePlannableResource)(nil)
|
||||
_ GraphNodeDynamicExpandable = (*NodePlannableResource)(nil)
|
||||
_ GraphNodeReferenceable = (*NodePlannableResource)(nil)
|
||||
|
@ -17,7 +17,7 @@ type NodePlanDestroyableResourceInstance struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodePlanDestroyableResourceInstance)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodePlanDestroyableResourceInstance)(nil)
|
||||
_ GraphNodeReferenceable = (*NodePlanDestroyableResourceInstance)(nil)
|
||||
_ GraphNodeReferencer = (*NodePlanDestroyableResourceInstance)(nil)
|
||||
_ GraphNodeDestroyer = (*NodePlanDestroyableResourceInstance)(nil)
|
||||
|
@ -20,7 +20,7 @@ type NodePlannableResourceInstance struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodePlannableResourceInstance)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodePlannableResourceInstance)(nil)
|
||||
_ GraphNodeReferenceable = (*NodePlannableResourceInstance)(nil)
|
||||
_ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil)
|
||||
_ GraphNodeResource = (*NodePlannableResourceInstance)(nil)
|
||||
|
@ -13,7 +13,7 @@ type NodePlannableResourceInstanceOrphan struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodePlannableResourceInstanceOrphan)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodePlannableResourceInstanceOrphan)(nil)
|
||||
_ GraphNodeReferenceable = (*NodePlannableResourceInstanceOrphan)(nil)
|
||||
_ GraphNodeReferencer = (*NodePlannableResourceInstanceOrphan)(nil)
|
||||
_ GraphNodeResource = (*NodePlannableResourceInstanceOrphan)(nil)
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -15,7 +15,7 @@ type NodeValidatableResource struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ GraphNodeSubPath = (*NodeValidatableResource)(nil)
|
||||
_ GraphNodeModuleInstance = (*NodeValidatableResource)(nil)
|
||||
_ GraphNodeEvalable = (*NodeValidatableResource)(nil)
|
||||
_ GraphNodeReferenceable = (*NodeValidatableResource)(nil)
|
||||
_ GraphNodeReferencer = (*NodeValidatableResource)(nil)
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
`
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user