opentofu/terraform/graph_config.go

105 lines
2.7 KiB
Go
Raw Normal View History

package terraform
import (
"errors"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
2015-01-22 19:12:32 -06:00
"github.com/hashicorp/terraform/dag"
)
// 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) {
// 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,
(len(config.ProviderConfigs)+len(config.Modules)+len(config.Resources))*2)
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})
}
// Write all the resources out
for _, r := range config.Resources {
2015-01-21 16:39:16 -06:00
nodes = append(nodes, &GraphNodeConfigResource{Resource: r})
}
// Write all the modules out
children := mod.Children()
for _, m := range config.Modules {
nodes = append(nodes, &GraphNodeConfigModule{
Module: m,
Tree: children[m.Name],
})
}
// Build the full map of the var names to the nodes.
2015-01-23 17:11:11 -06:00
fullMap := make(map[string]dag.Vertex)
for _, n := range nodes {
fullMap[n.VarName()] = n
}
2015-01-23 17:11:11 -06:00
// Build the graph vertices
var g dag.Graph
for _, n := range nodes {
g.Add(n)
}
// Err is where the final error value will go if there is one
var err error
2015-01-23 17:11:11 -06:00
// Go through all the nodes and build up the actual graph edges. 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 {
for _, id := range n.Variables() {
if id == "" {
// Empty name means its a variable we don't care about
continue
}
target, ok := fullMap[id]
if !ok {
// We can't find the target meaning the dependency
// is missing. Accumulate the error.
err = multierror.Append(err, fmt.Errorf(
"%s: missing dependency: %s", n, id))
continue
2015-01-23 17:11:11 -06:00
}
g.Connect(dag.BasicEdge(n, target))
}
}
return &g, err
}
// 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 ""
}
}