github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/graph_config_node_module.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/terraform/config" 8 "github.com/hashicorp/terraform/config/module" 9 "github.com/hashicorp/terraform/dag" 10 "github.com/hashicorp/terraform/dot" 11 ) 12 13 // GraphNodeConfigModule represents a module within the configuration graph. 14 type GraphNodeConfigModule struct { 15 Path []string 16 Module *config.Module 17 Tree *module.Tree 18 } 19 20 func (n *GraphNodeConfigModule) ConfigType() GraphNodeConfigType { 21 return GraphNodeConfigTypeModule 22 } 23 24 func (n *GraphNodeConfigModule) DependableName() []string { 25 config := n.Tree.Config() 26 27 result := make([]string, 1, len(config.Outputs)+1) 28 result[0] = n.Name() 29 for _, o := range config.Outputs { 30 result = append(result, fmt.Sprintf("%s.output.%s", n.Name(), o.Name)) 31 } 32 33 return result 34 } 35 36 func (n *GraphNodeConfigModule) DependentOn() []string { 37 vars := n.Module.RawConfig.Variables 38 result := make([]string, 0, len(vars)) 39 for _, v := range vars { 40 if vn := varNameForVar(v); vn != "" { 41 result = append(result, vn) 42 } 43 } 44 45 return result 46 } 47 48 func (n *GraphNodeConfigModule) Name() string { 49 return fmt.Sprintf("module.%s", n.Module.Name) 50 } 51 52 // GraphNodeExpandable 53 func (n *GraphNodeConfigModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) { 54 // Build the graph first 55 graph, err := b.Build(n.Path) 56 if err != nil { 57 return nil, err 58 } 59 60 // Add the parameters node to the module 61 t := &ModuleInputTransformer{Variables: make(map[string]string)} 62 if err := t.Transform(graph); err != nil { 63 return nil, err 64 } 65 66 { 67 // Add the destroy marker to the graph 68 t := &ModuleDestroyTransformer{} 69 if err := t.Transform(graph); err != nil { 70 return nil, err 71 } 72 } 73 74 // Build the actual subgraph node 75 return &graphNodeModuleExpanded{ 76 Original: n, 77 Graph: graph, 78 Variables: t.Variables, 79 }, nil 80 } 81 82 // GraphNodeExpandable 83 func (n *GraphNodeConfigModule) ProvidedBy() []string { 84 // Build up the list of providers by simply going over our configuration 85 // to find the providers that are configured there as well as the 86 // providers that the resources use. 87 config := n.Tree.Config() 88 providers := make(map[string]struct{}) 89 for _, p := range config.ProviderConfigs { 90 providers[p.Name] = struct{}{} 91 } 92 for _, r := range config.Resources { 93 providers[resourceProvider(r.Type, r.Provider)] = struct{}{} 94 } 95 96 // Turn the map into a string. This makes sure that the list is 97 // de-dupped since we could be going over potentially many resources. 98 result := make([]string, 0, len(providers)) 99 for p, _ := range providers { 100 result = append(result, p) 101 } 102 103 return result 104 } 105 106 // graphNodeModuleExpanded represents a module where the graph has 107 // been expanded. It stores the graph of the module as well as a reference 108 // to the map of variables. 109 type graphNodeModuleExpanded struct { 110 Original *GraphNodeConfigModule 111 Graph *Graph 112 113 // Variables is a map of the input variables. This reference should 114 // be shared with ModuleInputTransformer in order to create a connection 115 // where the variables are set properly. 116 Variables map[string]string 117 } 118 119 func (n *graphNodeModuleExpanded) Name() string { 120 return fmt.Sprintf("%s (expanded)", dag.VertexName(n.Original)) 121 } 122 123 func (n *graphNodeModuleExpanded) ConfigType() GraphNodeConfigType { 124 return GraphNodeConfigTypeModule 125 } 126 127 // GraphNodeDependable 128 func (n *graphNodeModuleExpanded) DependableName() []string { 129 return n.Original.DependableName() 130 } 131 132 // GraphNodeDependent 133 func (n *graphNodeModuleExpanded) DependentOn() []string { 134 return n.Original.DependentOn() 135 } 136 137 // GraphNodeDotter impl. 138 func (n *graphNodeModuleExpanded) DotNode(name string, opts *GraphDotOpts) *dot.Node { 139 return dot.NewNode(name, map[string]string{ 140 "label": dag.VertexName(n.Original), 141 "shape": "component", 142 }) 143 } 144 145 // GraphNodeEvalable impl. 146 func (n *graphNodeModuleExpanded) EvalTree() EvalNode { 147 var resourceConfig *ResourceConfig 148 return &EvalSequence{ 149 Nodes: []EvalNode{ 150 &EvalInterpolate{ 151 Config: n.Original.Module.RawConfig, 152 Output: &resourceConfig, 153 }, 154 155 &EvalVariableBlock{ 156 Config: &resourceConfig, 157 Variables: n.Variables, 158 }, 159 }, 160 } 161 } 162 163 // GraphNodeFlattenable impl. 164 func (n *graphNodeModuleExpanded) FlattenGraph() *Graph { 165 graph := n.Subgraph() 166 input := n.Original.Module.RawConfig 167 168 // Go over each vertex and do some modifications to the graph for 169 // flattening. We have to skip some nodes (graphNodeModuleSkippable) 170 // as well as setup the variable values. 171 for _, v := range graph.Vertices() { 172 if sn, ok := v.(graphNodeModuleSkippable); ok && sn.FlattenSkip() { 173 graph.Remove(v) 174 continue 175 } 176 177 // If this is a variable, then look it up in the raw configuration. 178 // If it exists in the raw configuration, set the value of it. 179 if vn, ok := v.(*GraphNodeConfigVariable); ok && input != nil { 180 key := vn.VariableName() 181 if v, ok := input.Raw[key]; ok { 182 config, err := config.NewRawConfig(map[string]interface{}{ 183 key: v, 184 }) 185 if err != nil { 186 // This shouldn't happen because it is already in 187 // a RawConfig above meaning it worked once before. 188 panic(err) 189 } 190 191 // Set the variable value so it is interpolated properly. 192 // Also set the module so we set the value on it properly. 193 vn.Module = graph.Path[len(graph.Path)-1] 194 vn.Value = config 195 } 196 } 197 } 198 199 return graph 200 } 201 202 // GraphNodeSubgraph impl. 203 func (n *graphNodeModuleExpanded) Subgraph() *Graph { 204 return n.Graph 205 } 206 207 // This interface can be implemented to be skipped/ignored when 208 // flattening the module graph. 209 type graphNodeModuleSkippable interface { 210 FlattenSkip() bool 211 } 212 213 func modulePrefixStr(p []string) string { 214 parts := make([]string, 0, len(p)*2) 215 for _, p := range p[1:] { 216 parts = append(parts, "module", p) 217 } 218 219 return strings.Join(parts, ".") 220 } 221 222 func modulePrefixList(result []string, prefix string) []string { 223 if prefix != "" { 224 for i, v := range result { 225 result[i] = fmt.Sprintf("%s.%s", prefix, v) 226 } 227 } 228 229 return result 230 }