From a73f939ee9f3e638c5376f21c2259dbedf7ef392 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Feb 2015 12:04:02 +0100 Subject: [PATCH] terraform: initial GraphBuilder impl --- terraform/graph_builder.go | 58 +++++++++++++++++++ terraform/graph_builder_test.go | 39 +++++++++++++ .../test-fixtures/graph-builder-basic/main.tf | 5 ++ 3 files changed, 102 insertions(+) create mode 100644 terraform/graph_builder.go create mode 100644 terraform/graph_builder_test.go create mode 100644 terraform/test-fixtures/graph-builder-basic/main.tf diff --git a/terraform/graph_builder.go b/terraform/graph_builder.go new file mode 100644 index 000000000..6274171a0 --- /dev/null +++ b/terraform/graph_builder.go @@ -0,0 +1,58 @@ +package terraform + +import ( + "github.com/hashicorp/terraform/config/module" +) + +// GraphBuilder is an interface that can be implemented and used with +// Terraform to build the graph that Terraform walks. +type GraphBuilder interface { + // Build builds the graph for the given module path. It is up to + // the interface implementation whether this build should expand + // the graph or not. + Build(path []string) (*Graph, error) +} + +// BuiltinGraphBuilder is responsible for building the complete graph that +// Terraform uses for execution. It is an opinionated builder that defines +// the step order required to build a complete graph as is used and expected +// by Terraform. +// +// If you require a custom graph, you'll have to build it up manually +// on your own by building a new GraphBuilder implementation. +type BuiltinGraphBuilder struct { + // Root is the root module of the graph to build. + Root *module.Tree + + // State is the global state. The proper module states will be looked + // up by graph path. + State *State + + // Providers is the list of providers supported. + Providers []string +} + +// Build builds the graph according to the steps returned by Steps. +func (b *BuiltinGraphBuilder) Build(path []string) (*Graph, error) { + g := &Graph{Path: path} + for _, step := range b.Steps() { + if err := step.Transform(g); err != nil { + return g, err + } + } + + return g, nil +} + +// Steps returns the ordered list of GraphTransformers that must be executed +// to build a complete graph. +func (b *BuiltinGraphBuilder) Steps() []GraphTransformer { + return []GraphTransformer{ + &ConfigTransformer{Module: b.Root}, + &OrphanTransformer{State: b.State, Module: b.Root}, + &TaintedTransformer{State: b.State}, + &MissingProviderTransformer{Providers: b.Providers}, + &ProviderTransformer{}, + &PruneProviderTransformer{}, + } +} diff --git a/terraform/graph_builder_test.go b/terraform/graph_builder_test.go new file mode 100644 index 000000000..a353fa0b3 --- /dev/null +++ b/terraform/graph_builder_test.go @@ -0,0 +1,39 @@ +package terraform + +import ( + "strings" + "testing" +) + +func TestBuiltinGraphBuilder_impl(t *testing.T) { + var _ GraphBuilder = new(BuiltinGraphBuilder) +} + +// This test is not meant to test all the transforms but rather just +// to verify we get some basic sane graph out. Special tests to ensure +// specific ordering of steps should be added in other tests. +func TestBuiltinGraphBuilder(t *testing.T) { + b := &BuiltinGraphBuilder{ + Root: testModule(t, "graph-builder-basic"), + } + + g, err := b.Build(RootModulePath) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testBuiltinGraphBuilderBasicStr) + if actual != expected { + t.Fatalf("bad: %s", actual) + } +} + +const testBuiltinGraphBuilderBasicStr = ` +aws_instance.db + provider.aws +aws_instance.web + aws_instance.db + provider.aws +provider.aws +` diff --git a/terraform/test-fixtures/graph-builder-basic/main.tf b/terraform/test-fixtures/graph-builder-basic/main.tf new file mode 100644 index 000000000..add0dd43f --- /dev/null +++ b/terraform/test-fixtures/graph-builder-basic/main.tf @@ -0,0 +1,5 @@ +provider "aws" {} +resource "aws_instance" "db" {} +resource "aws_instance" "web" { + foo = "${aws_instance.db.id}" +}