2015-01-21 16:20:51 -06:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/config"
|
|
|
|
"github.com/hashicorp/terraform/config/module"
|
2015-01-22 19:12:32 -06:00
|
|
|
"github.com/hashicorp/terraform/dag"
|
2015-01-21 16:20:51 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// Graph takes a module tree and builds a logical graph of all the nodes
|
|
|
|
// in that module.
|
2015-01-22 19:12:32 -06:00
|
|
|
func Graph2(mod *module.Tree) (*dag.Graph, error) {
|
2015-01-21 16:20:51 -06:00
|
|
|
// A module is required and also must be completely loaded.
|
|
|
|
if mod == nil {
|
|
|
|
return nil, errors.New("module must not be nil")
|
|
|
|
}
|
|
|
|
if !mod.Loaded() {
|
|
|
|
return nil, errors.New("module must be loaded")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the configuration for this module
|
|
|
|
config := mod.Config()
|
|
|
|
|
|
|
|
// Create the node list we'll use for the graph
|
|
|
|
nodes := make([]graphNodeConfig, 0,
|
2015-01-21 16:53:50 -06:00
|
|
|
(len(config.ProviderConfigs)+len(config.Modules)+len(config.Resources))*2)
|
2015-01-21 16:20:51 -06:00
|
|
|
|
2015-01-21 16:39:16 -06:00
|
|
|
// Write all the provider configs out
|
|
|
|
for _, pc := range config.ProviderConfigs {
|
|
|
|
nodes = append(nodes, &GraphNodeConfigProvider{Provider: pc})
|
|
|
|
}
|
|
|
|
|
2015-01-21 16:20:51 -06:00
|
|
|
// Write all the resources out
|
|
|
|
for _, r := range config.Resources {
|
2015-01-21 16:39:16 -06:00
|
|
|
nodes = append(nodes, &GraphNodeConfigResource{Resource: r})
|
2015-01-21 16:20:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write all the modules out
|
2015-01-21 16:53:50 -06:00
|
|
|
for _, m := range config.Modules {
|
|
|
|
nodes = append(nodes, &GraphNodeConfigModule{Module: m})
|
|
|
|
}
|
2015-01-21 16:20:51 -06:00
|
|
|
|
|
|
|
// Build the full map of the var names to the nodes.
|
2015-01-22 19:12:32 -06:00
|
|
|
fullMap := make(map[string]dag.Node)
|
2015-01-21 16:20:51 -06:00
|
|
|
for _, n := range nodes {
|
|
|
|
fullMap[n.VarName()] = n
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go through all the nodes and build up the actual dependency map. We
|
|
|
|
// do this by getting the variables that each node depends on and then
|
|
|
|
// building the dep map based on the fullMap which contains the mapping
|
|
|
|
// of var names to the actual node with that name.
|
|
|
|
for _, n := range nodes {
|
2015-01-22 19:12:32 -06:00
|
|
|
m := make(map[string]dag.Node)
|
2015-01-21 17:37:17 -06:00
|
|
|
for _, id := range n.Variables() {
|
2015-01-21 16:20:51 -06:00
|
|
|
m[id] = fullMap[id]
|
|
|
|
}
|
|
|
|
|
|
|
|
n.setDepMap(m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the graph and return it
|
2015-01-22 19:12:32 -06:00
|
|
|
g := &dag.Graph{Nodes: make([]dag.Node, 0, len(nodes))}
|
2015-01-21 16:20:51 -06:00
|
|
|
for _, n := range nodes {
|
|
|
|
g.Nodes = append(g.Nodes, n)
|
|
|
|
}
|
|
|
|
|
|
|
|
return g, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// varNameForVar returns the VarName value for an interpolated variable.
|
|
|
|
// This value is compared to the VarName() value for the nodes within the
|
|
|
|
// graph to build the graph edges.
|
|
|
|
func varNameForVar(raw config.InterpolatedVariable) string {
|
|
|
|
switch v := raw.(type) {
|
|
|
|
case *config.ModuleVariable:
|
|
|
|
return fmt.Sprintf("module.%s", v.Name)
|
|
|
|
case *config.ResourceVariable:
|
|
|
|
return v.ResourceId()
|
|
|
|
default:
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|