github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/node_module_variable.go (about)

     1  package terraform
     2  
     3  import (
     4  	"github.com/hashicorp/hcl/v2"
     5  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
     6  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
     7  	"github.com/hashicorp/terraform-plugin-sdk/internal/dag"
     8  	"github.com/hashicorp/terraform-plugin-sdk/internal/lang"
     9  	"github.com/zclconf/go-cty/cty"
    10  )
    11  
    12  // NodeApplyableModuleVariable represents a module variable input during
    13  // the apply step.
    14  type NodeApplyableModuleVariable struct {
    15  	Addr   addrs.AbsInputVariableInstance
    16  	Config *configs.Variable // Config is the var in the config
    17  	Expr   hcl.Expression    // Expr is the value expression given in the call
    18  }
    19  
    20  // Ensure that we are implementing all of the interfaces we think we are
    21  // implementing.
    22  var (
    23  	_ GraphNodeSubPath          = (*NodeApplyableModuleVariable)(nil)
    24  	_ RemovableIfNotTargeted    = (*NodeApplyableModuleVariable)(nil)
    25  	_ GraphNodeReferenceOutside = (*NodeApplyableModuleVariable)(nil)
    26  	_ GraphNodeReferenceable    = (*NodeApplyableModuleVariable)(nil)
    27  	_ GraphNodeReferencer       = (*NodeApplyableModuleVariable)(nil)
    28  	_ GraphNodeEvalable         = (*NodeApplyableModuleVariable)(nil)
    29  	_ dag.GraphNodeDotter       = (*NodeApplyableModuleVariable)(nil)
    30  )
    31  
    32  func (n *NodeApplyableModuleVariable) Name() string {
    33  	return n.Addr.String()
    34  }
    35  
    36  // GraphNodeSubPath
    37  func (n *NodeApplyableModuleVariable) Path() addrs.ModuleInstance {
    38  	// We execute in the parent scope (above our own module) because
    39  	// expressions in our value are resolved in that context.
    40  	return n.Addr.Module.Parent()
    41  }
    42  
    43  // RemovableIfNotTargeted
    44  func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool {
    45  	// We need to add this so that this node will be removed if
    46  	// it isn't targeted or a dependency of a target.
    47  	return true
    48  }
    49  
    50  // GraphNodeReferenceOutside implementation
    51  func (n *NodeApplyableModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.ModuleInstance) {
    52  
    53  	// Module input variables have their value expressions defined in the
    54  	// context of their calling (parent) module, and so references from
    55  	// a node of this type should be resolved in the parent module instance.
    56  	referencePath = n.Addr.Module.Parent()
    57  
    58  	// Input variables are _referenced_ from their own module, though.
    59  	selfPath = n.Addr.Module
    60  
    61  	return // uses named return values
    62  }
    63  
    64  // GraphNodeReferenceable
    65  func (n *NodeApplyableModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
    66  	return []addrs.Referenceable{n.Addr.Variable}
    67  }
    68  
    69  // GraphNodeReferencer
    70  func (n *NodeApplyableModuleVariable) References() []*addrs.Reference {
    71  
    72  	// If we have no value expression, we cannot depend on anything.
    73  	if n.Expr == nil {
    74  		return nil
    75  	}
    76  
    77  	// Variables in the root don't depend on anything, because their values
    78  	// are gathered prior to the graph walk and recorded in the context.
    79  	if len(n.Addr.Module) == 0 {
    80  		return nil
    81  	}
    82  
    83  	// Otherwise, we depend on anything referenced by our value expression.
    84  	// We ignore diagnostics here under the assumption that we'll re-eval
    85  	// all these things later and catch them then; for our purposes here,
    86  	// we only care about valid references.
    87  	//
    88  	// Due to our GraphNodeReferenceOutside implementation, the addresses
    89  	// returned by this function are interpreted in the _parent_ module from
    90  	// where our associated variable was declared, which is correct because
    91  	// our value expression is assigned within a "module" block in the parent
    92  	// module.
    93  	refs, _ := lang.ReferencesInExpr(n.Expr)
    94  	return refs
    95  }
    96  
    97  // GraphNodeEvalable
    98  func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
    99  	// If we have no value, do nothing
   100  	if n.Expr == nil {
   101  		return &EvalNoop{}
   102  	}
   103  
   104  	// Otherwise, interpolate the value of this variable and set it
   105  	// within the variables mapping.
   106  	vals := make(map[string]cty.Value)
   107  
   108  	_, call := n.Addr.Module.CallInstance()
   109  
   110  	return &EvalSequence{
   111  		Nodes: []EvalNode{
   112  			&EvalOpFilter{
   113  				Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
   114  					walkDestroy, walkValidate},
   115  				Node: &EvalModuleCallArgument{
   116  					Addr:   n.Addr.Variable,
   117  					Config: n.Config,
   118  					Expr:   n.Expr,
   119  					Values: vals,
   120  
   121  					IgnoreDiagnostics: false,
   122  				},
   123  			},
   124  
   125  			&EvalSetModuleCallArguments{
   126  				Module: call,
   127  				Values: vals,
   128  			},
   129  		},
   130  	}
   131  }
   132  
   133  // dag.GraphNodeDotter impl.
   134  func (n *NodeApplyableModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   135  	return &dag.DotNode{
   136  		Name: name,
   137  		Attrs: map[string]string{
   138  			"label": n.Name(),
   139  			"shape": "note",
   140  		},
   141  	}
   142  }