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  }