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 }