From 9f70cddadf4e32d1dd170673dd1ed88a2146e29f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 23 Jan 2015 15:21:27 -0800 Subject: [PATCH] terraform: error if config graph is missing dependencies --- terraform/graph_config.go | 22 ++++++++++++++++--- terraform/graph_config_node.go | 2 +- terraform/graph_config_test.go | 7 ++++++ .../test-fixtures/graph-missing-deps/main.tf | 5 +++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 terraform/test-fixtures/graph-missing-deps/main.tf diff --git a/terraform/graph_config.go b/terraform/graph_config.go index dd6a7f9b9..ca02c697d 100644 --- a/terraform/graph_config.go +++ b/terraform/graph_config.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/dag" @@ -54,19 +55,34 @@ func Graph2(mod *module.Tree) (*dag.Graph, error) { g.Add(n) } + // Err is where the final error value will go if there is one + var err error + // 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 target, ok := fullMap[id]; ok { - g.Connect(dag.BasicEdge(n, target)) + 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 + } + + g.Connect(dag.BasicEdge(n, target)) } } - return &g, nil + return &g, err } // varNameForVar returns the VarName value for an interpolated variable. diff --git a/terraform/graph_config_node.go b/terraform/graph_config_node.go index 843a017e8..cc0e43202 100644 --- a/terraform/graph_config_node.go +++ b/terraform/graph_config_node.go @@ -11,7 +11,7 @@ import ( // configuration graph need to implement in order to build the variable // dependencies properly. type graphNodeConfig interface { - dag.Vertex + dag.NamedVertex // Variables returns the full list of variables that this node // depends on. The values within the slice should map to the VarName() diff --git a/terraform/graph_config_test.go b/terraform/graph_config_test.go index e8fe51d16..3bd22dc69 100644 --- a/terraform/graph_config_test.go +++ b/terraform/graph_config_test.go @@ -66,6 +66,13 @@ func TestGraph2_modules(t *testing.T) { } } +func TestGraph2_errMissingDeps(t *testing.T) { + _, err := Graph2(testModule(t, "graph-missing-deps")) + if err == nil { + t.Fatal("should error") + } +} + const testGraphBasicStr = ` aws_instance.web aws_security_group.firewall diff --git a/terraform/test-fixtures/graph-missing-deps/main.tf b/terraform/test-fixtures/graph-missing-deps/main.tf new file mode 100644 index 000000000..44297f318 --- /dev/null +++ b/terraform/test-fixtures/graph-missing-deps/main.tf @@ -0,0 +1,5 @@ +resource "aws_instance" "db" {} + +resource "aws_instance" "web" { + foo = "${aws_instance.lb.id}" +}