github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/terraform/graph_config_node_variable.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/config"
     7  	"github.com/hashicorp/terraform/config/module"
     8  	"github.com/hashicorp/terraform/dag"
     9  )
    10  
    11  // GraphNodeConfigVariable represents a Variable in the config.
    12  type GraphNodeConfigVariable struct {
    13  	Variable *config.Variable
    14  
    15  	// Value, if non-nil, will be used to set the value of the variable
    16  	// during evaluation. If this is nil, evaluation will do nothing.
    17  	//
    18  	// Module is the name of the module to set the variables on.
    19  	Module string
    20  	Value  *config.RawConfig
    21  
    22  	ModuleTree *module.Tree
    23  	ModulePath []string
    24  }
    25  
    26  func (n *GraphNodeConfigVariable) Name() string {
    27  	return fmt.Sprintf("var.%s", n.Variable.Name)
    28  }
    29  
    30  func (n *GraphNodeConfigVariable) ConfigType() GraphNodeConfigType {
    31  	return GraphNodeConfigTypeVariable
    32  }
    33  
    34  func (n *GraphNodeConfigVariable) DependableName() []string {
    35  	return []string{n.Name()}
    36  }
    37  
    38  func (n *GraphNodeConfigVariable) DependentOn() []string {
    39  	// If we don't have any value set, we don't depend on anything
    40  	if n.Value == nil {
    41  		return nil
    42  	}
    43  
    44  	// Get what we depend on based on our value
    45  	vars := n.Value.Variables
    46  	result := make([]string, 0, len(vars))
    47  	for _, v := range vars {
    48  		if vn := varNameForVar(v); vn != "" {
    49  			result = append(result, vn)
    50  		}
    51  	}
    52  
    53  	return result
    54  }
    55  
    56  func (n *GraphNodeConfigVariable) VariableName() string {
    57  	return n.Variable.Name
    58  }
    59  
    60  // GraphNodeDestroyEdgeInclude impl.
    61  func (n *GraphNodeConfigVariable) DestroyEdgeInclude(v dag.Vertex) bool {
    62  	// Only include this variable in a destroy edge if the source vertex
    63  	// "v" has a count dependency on this variable.
    64  	cv, ok := v.(GraphNodeCountDependent)
    65  	if !ok {
    66  		return false
    67  	}
    68  
    69  	for _, d := range cv.CountDependentOn() {
    70  		for _, d2 := range n.DependableName() {
    71  			if d == d2 {
    72  				return true
    73  			}
    74  		}
    75  	}
    76  
    77  	return false
    78  }
    79  
    80  // GraphNodeNoopPrunable
    81  func (n *GraphNodeConfigVariable) Noop(opts *NoopOpts) bool {
    82  	// If we have no diff, always keep this in the graph. We have to do
    83  	// this primarily for validation: we want to validate that variable
    84  	// interpolations are valid even if there are no resources that
    85  	// depend on them.
    86  	if opts.Diff == nil || opts.Diff.Empty() {
    87  		return false
    88  	}
    89  
    90  	for _, v := range opts.Graph.UpEdges(opts.Vertex).List() {
    91  		// This is terrible, but I can't think of a better way to do this.
    92  		if dag.VertexName(v) == rootNodeName {
    93  			continue
    94  		}
    95  
    96  		return false
    97  	}
    98  
    99  	return true
   100  }
   101  
   102  // GraphNodeProxy impl.
   103  func (n *GraphNodeConfigVariable) Proxy() bool {
   104  	return true
   105  }
   106  
   107  // GraphNodeEvalable impl.
   108  func (n *GraphNodeConfigVariable) EvalTree() EvalNode {
   109  	// If we have no value, do nothing
   110  	if n.Value == nil {
   111  		return &EvalNoop{}
   112  	}
   113  
   114  	// Otherwise, interpolate the value of this variable and set it
   115  	// within the variables mapping.
   116  	var config *ResourceConfig
   117  	variables := make(map[string]string)
   118  	return &EvalSequence{
   119  		Nodes: []EvalNode{
   120  			&EvalInterpolate{
   121  				Config: n.Value,
   122  				Output: &config,
   123  			},
   124  
   125  			&EvalVariableBlock{
   126  				Config:    &config,
   127  				Variables: variables,
   128  			},
   129  
   130  			&EvalTypeCheckVariable{
   131  				Variables:  variables,
   132  				ModulePath: n.ModulePath,
   133  				ModuleTree: n.ModuleTree,
   134  			},
   135  
   136  			&EvalSetVariables{
   137  				Module:    &n.Module,
   138  				Variables: variables,
   139  			},
   140  		},
   141  	}
   142  }
   143  
   144  // GraphNodeFlattenable impl.
   145  func (n *GraphNodeConfigVariable) Flatten(p []string) (dag.Vertex, error) {
   146  	return &GraphNodeConfigVariableFlat{
   147  		GraphNodeConfigVariable: n,
   148  		PathValue:               p,
   149  	}, nil
   150  }
   151  
   152  type GraphNodeConfigVariableFlat struct {
   153  	*GraphNodeConfigVariable
   154  
   155  	PathValue []string
   156  }
   157  
   158  func (n *GraphNodeConfigVariableFlat) Name() string {
   159  	return fmt.Sprintf(
   160  		"%s.%s", modulePrefixStr(n.PathValue), n.GraphNodeConfigVariable.Name())
   161  }
   162  
   163  func (n *GraphNodeConfigVariableFlat) DependableName() []string {
   164  	return []string{n.Name()}
   165  }
   166  
   167  func (n *GraphNodeConfigVariableFlat) DependentOn() []string {
   168  	// We only wrap the dependencies and such if we have a path that is
   169  	// longer than 2 elements (root, child, more). This is because when
   170  	// flattened, variables can point outside the graph.
   171  	prefix := ""
   172  	if len(n.PathValue) > 2 {
   173  		prefix = modulePrefixStr(n.PathValue[:len(n.PathValue)-1])
   174  	}
   175  
   176  	return modulePrefixList(
   177  		n.GraphNodeConfigVariable.DependentOn(),
   178  		prefix)
   179  }
   180  
   181  func (n *GraphNodeConfigVariableFlat) Path() []string {
   182  	if len(n.PathValue) > 2 {
   183  		return n.PathValue[:len(n.PathValue)-1]
   184  	}
   185  
   186  	return nil
   187  }