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