github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/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 { 61 // Add the destroy marker to the graph 62 t := &ModuleDestroyTransformer{} 63 if err := t.Transform(graph); err != nil { 64 return nil, err 65 } 66 } 67 68 // Build the actual subgraph node 69 return &graphNodeModuleExpanded{ 70 Original: n, 71 Graph: graph, 72 Variables: make(map[string]interface{}), 73 }, nil 74 } 75 76 // GraphNodeExpandable 77 func (n *GraphNodeConfigModule) ProvidedBy() []string { 78 // Build up the list of providers by simply going over our configuration 79 // to find the providers that are configured there as well as the 80 // providers that the resources use. 81 config := n.Tree.Config() 82 providers := make(map[string]struct{}) 83 for _, p := range config.ProviderConfigs { 84 providers[p.Name] = struct{}{} 85 } 86 for _, r := range config.Resources { 87 providers[resourceProvider(r.Type, r.Provider)] = struct{}{} 88 } 89 90 // Turn the map into a string. This makes sure that the list is 91 // de-dupped since we could be going over potentially many resources. 92 result := make([]string, 0, len(providers)) 93 for p, _ := range providers { 94 result = append(result, p) 95 } 96 97 return result 98 } 99 100 // graphNodeModuleExpanded represents a module where the graph has 101 // been expanded. It stores the graph of the module as well as a reference 102 // to the map of variables. 103 type graphNodeModuleExpanded struct { 104 Original *GraphNodeConfigModule 105 Graph *Graph 106 107 // Variables is a map of the input variables. This reference should 108 // be shared with ModuleInputTransformer in order to create a connection 109 // where the variables are set properly. 110 Variables map[string]interface{} 111 } 112 113 func (n *graphNodeModuleExpanded) Name() string { 114 return fmt.Sprintf("%s (expanded)", dag.VertexName(n.Original)) 115 } 116 117 func (n *graphNodeModuleExpanded) ConfigType() GraphNodeConfigType { 118 return GraphNodeConfigTypeModule 119 } 120 121 // GraphNodeDependable 122 func (n *graphNodeModuleExpanded) DependableName() []string { 123 return n.Original.DependableName() 124 } 125 126 // GraphNodeDependent 127 func (n *graphNodeModuleExpanded) DependentOn() []string { 128 return n.Original.DependentOn() 129 } 130 131 // GraphNodeDotter impl. 132 func (n *graphNodeModuleExpanded) DotNode(name string, opts *GraphDotOpts) *dot.Node { 133 return dot.NewNode(name, map[string]string{ 134 "label": dag.VertexName(n.Original), 135 "shape": "component", 136 }) 137 } 138 139 // GraphNodeEvalable impl. 140 func (n *graphNodeModuleExpanded) EvalTree() EvalNode { 141 var resourceConfig *ResourceConfig 142 return &EvalSequence{ 143 Nodes: []EvalNode{ 144 &EvalInterpolate{ 145 Config: n.Original.Module.RawConfig, 146 Output: &resourceConfig, 147 }, 148 149 &EvalVariableBlock{ 150 Config: &resourceConfig, 151 VariableValues: n.Variables, 152 }, 153 }, 154 } 155 } 156 157 // GraphNodeFlattenable impl. 158 func (n *graphNodeModuleExpanded) FlattenGraph() *Graph { 159 graph := n.Subgraph() 160 input := n.Original.Module.RawConfig 161 162 // Go over each vertex and do some modifications to the graph for 163 // flattening. We have to skip some nodes (graphNodeModuleSkippable) 164 // as well as setup the variable values. 165 for _, v := range graph.Vertices() { 166 // If this is a variable, then look it up in the raw configuration. 167 // If it exists in the raw configuration, set the value of it. 168 if vn, ok := v.(*GraphNodeConfigVariable); ok && input != nil { 169 key := vn.VariableName() 170 if v, ok := input.Raw[key]; ok { 171 config, err := config.NewRawConfig(map[string]interface{}{ 172 key: v, 173 }) 174 if err != nil { 175 // This shouldn't happen because it is already in 176 // a RawConfig above meaning it worked once before. 177 panic(err) 178 } 179 180 // Set the variable value so it is interpolated properly. 181 // Also set the module so we set the value on it properly. 182 vn.Module = graph.Path[len(graph.Path)-1] 183 vn.Value = config 184 } 185 } 186 } 187 188 return graph 189 } 190 191 // GraphNodeSubgraph impl. 192 func (n *graphNodeModuleExpanded) Subgraph() *Graph { 193 return n.Graph 194 } 195 196 func modulePrefixStr(p []string) string { 197 parts := make([]string, 0, len(p)*2) 198 for _, p := range p[1:] { 199 parts = append(parts, "module", p) 200 } 201 202 return strings.Join(parts, ".") 203 } 204 205 func modulePrefixList(result []string, prefix string) []string { 206 if prefix != "" { 207 for i, v := range result { 208 result[i] = fmt.Sprintf("%s.%s", prefix, v) 209 } 210 } 211 212 return result 213 }