From d731d033f10844dd53616a83b4edd84c1ff58186 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Jun 2014 17:14:19 -0700 Subject: [PATCH] terraform: build resource graph, validate --- config/config.go | 6 +++++- terraform/state.go | 14 +------------- terraform/terraform.go | 10 ++++++++++ terraform/terraform_test.go | 18 ++++++++++++++++++ .../test-fixtures/new-graph-cycle/main.tf | 7 +++++++ 5 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 terraform/test-fixtures/new-graph-cycle/main.tf diff --git a/config/config.go b/config/config.go index 464bef5b7..44388970c 100644 --- a/config/config.go +++ b/config/config.go @@ -9,6 +9,10 @@ import ( "github.com/hashicorp/terraform/depgraph" ) +// ResourceGraphRoot is the name of the resource graph root that should be +// ignored since it doesn't map to an exact resource. +const ResourceGraphRoot = "root" + // Config is the configuration that comes from loading a collection // of Terraform templates. type Config struct { @@ -116,7 +120,7 @@ func (c *Config) ResourceGraph() *depgraph.Graph { } // Create a root that just depends on everything else finishing. - root := &depgraph.Noun{Name: "root"} + root := &depgraph.Noun{Name: ResourceGraphRoot} for _, n := range nounsList { root.Deps = append(root.Deps, &depgraph.Dependency{ Name: n.Name, diff --git a/terraform/state.go b/terraform/state.go index 812b1133e..daffb726a 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -4,17 +4,5 @@ package terraform // can use to keep track of what real world resources it is actually // managing. type State struct { - resources map[string]resourceState -} - -// resourceState is the state of a single resource. -// -// The ID is required and is some opaque string used to recognize -// the realized resource. -// -// Extra is arbitrary extra metadata that the resource provider returns -// that is sent back into the resource provider when it is needed. -type resourceState struct { - ID string - Extra map[string]interface{} + resources map[string]ResourceState } diff --git a/terraform/terraform.go b/terraform/terraform.go index 8abf83724..3634a133f 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/hashicorp/terraform/config" + "github.com/hashicorp/terraform/depgraph" ) // Terraform is the primary structure that is used to interact with @@ -12,6 +13,7 @@ import ( // all resources, a resource tree, a specific resource, etc. type Terraform struct { config *config.Config + graph *depgraph.Graph mapping map[*config.Resource]ResourceProvider variables map[string]string } @@ -98,6 +100,13 @@ func New(c *Config) (*Terraform, error) { mapping[r] = provider } + // Build the resource graph + graph := c.Config.ResourceGraph() + if err := graph.Validate(); err != nil { + errs = append(errs, fmt.Errorf( + "Resource graph has an error: %s", err)) + } + // If we accumulated any errors, then return them all if len(errs) > 0 { return nil, &MultiError{Errors: errs} @@ -105,6 +114,7 @@ func New(c *Config) (*Terraform, error) { return &Terraform{ config: c.Config, + graph: graph, mapping: mapping, variables: c.Variables, }, nil diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 4053a900f..1821257d3 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -80,6 +80,24 @@ func TestNew(t *testing.T) { } } +func TestNew_graphCycle(t *testing.T) { + config := testConfig(t, "new-graph-cycle") + tfConfig := &Config{ + Config: config, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFunc("aws", []string{"aws_instance"}), + }, + } + + tf, err := New(tfConfig) + if err == nil { + t.Fatal("should error") + } + if tf != nil { + t.Fatalf("should not return tf") + } +} + func TestNew_variables(t *testing.T) { config := testConfig(t, "new-variables") tfConfig := &Config{ diff --git a/terraform/test-fixtures/new-graph-cycle/main.tf b/terraform/test-fixtures/new-graph-cycle/main.tf new file mode 100644 index 000000000..a292b8706 --- /dev/null +++ b/terraform/test-fixtures/new-graph-cycle/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" { + ami = "${aws_instance.bar.id}" +} + +resource "aws_instance" "bar" { + ami = "${aws_instance.foo.id}" +}