From 29eadb8194f333fd6cd133da7d14fb3bdf1db0c6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 24 Jun 2015 20:58:52 -0700 Subject: [PATCH] terraform: missing provider should add missing aliases [GH-2023] --- config/config.go | 4 ++ terraform/context_test.go | 65 ++++++++----------- terraform/terraform_test.go | 8 +++ .../apply-module-provider-alias/child/main.tf | 7 ++ .../apply-module-provider-alias/main.tf | 3 + .../apply-provider-alias-missing/main.tf | 8 --- .../transform-provider-missing/main.tf | 3 + terraform/transform_provider.go | 40 ++++++++++-- terraform/transform_provider_test.go | 7 +- 9 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 terraform/test-fixtures/apply-module-provider-alias/child/main.tf create mode 100644 terraform/test-fixtures/apply-module-provider-alias/main.tf delete mode 100644 terraform/test-fixtures/apply-provider-alias-missing/main.tf create mode 100644 terraform/test-fixtures/transform-provider-missing/main.tf diff --git a/config/config.go b/config/config.go index 06688d31d..811b77ec7 100644 --- a/config/config.go +++ b/config/config.go @@ -683,6 +683,10 @@ func (o *Output) mergerMerge(m merger) merger { return &result } +func (c *ProviderConfig) GoString() string { + return fmt.Sprintf("*%#v", *c) +} + func (c *ProviderConfig) FullName() string { if c.Alias == "" { return c.Name diff --git a/terraform/context_test.go b/terraform/context_test.go index db16e4e08..4a92c308e 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -697,43 +697,6 @@ func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { } } -func TestContext2Plan_providerAliasMissing(t *testing.T) { - m := testModule(t, "apply-provider-alias-missing") - p := testProvider("aws") - p.ApplyFn = testApplyFn - p.DiffFn = testDiffFn - state := &State{ - Modules: []*ModuleState{ - &ModuleState{ - Path: rootModulePath, - Resources: map[string]*ResourceState{ - "aws_instance.foo": &ResourceState{ - Type: "aws_instance", - Provider: "aws.foo", - Primary: &InstanceState{ - ID: "bar", - Attributes: map[string]string{ - "require_new": "abc", - }, - }, - }, - }, - }, - }, - } - ctx := testContext2(t, &ContextOpts{ - Module: m, - Providers: map[string]ResourceProviderFactory{ - "aws": testProviderFuncFixed(p), - }, - State: state, - }) - - if _, err := ctx.Plan(); err == nil { - t.Fatal("should err") - } -} - func TestContext2Plan_computed(t *testing.T) { m := testModule(t, "plan-computed") p := testProvider("aws") @@ -4375,6 +4338,34 @@ func TestContext2Apply_moduleDestroyOrder(t *testing.T) { } } +func TestContext2Apply_moduleProviderAlias(t *testing.T) { + m := testModule(t, "apply-module-provider-alias") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err := ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContext2Apply_moduleVarResourceCount(t *testing.T) { m := testModule(t, "apply-module-var-resource-count") p := testProvider("aws") diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 269df7298..4ec622583 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -379,6 +379,14 @@ do_instance.foo: type = do_instance ` +const testTerraformApplyModuleProviderAliasStr = ` + +module.child: + aws_instance.foo: + ID = foo + provider = aws.eu +` + const testTerraformApplyOutputOrphanStr = ` Outputs: diff --git a/terraform/test-fixtures/apply-module-provider-alias/child/main.tf b/terraform/test-fixtures/apply-module-provider-alias/child/main.tf new file mode 100644 index 000000000..ee923f255 --- /dev/null +++ b/terraform/test-fixtures/apply-module-provider-alias/child/main.tf @@ -0,0 +1,7 @@ +provider "aws" { + alias = "eu" +} + +resource "aws_instance" "foo" { + provider = "aws.eu" +} diff --git a/terraform/test-fixtures/apply-module-provider-alias/main.tf b/terraform/test-fixtures/apply-module-provider-alias/main.tf new file mode 100644 index 000000000..0f6991c53 --- /dev/null +++ b/terraform/test-fixtures/apply-module-provider-alias/main.tf @@ -0,0 +1,3 @@ +module "child" { + source = "./child" +} diff --git a/terraform/test-fixtures/apply-provider-alias-missing/main.tf b/terraform/test-fixtures/apply-provider-alias-missing/main.tf deleted file mode 100644 index ea50084fd..000000000 --- a/terraform/test-fixtures/apply-provider-alias-missing/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "aws" { - alias = "bar" -} - -resource "aws_instance" "bar" { - foo = "bar" - provider = "aws.bar" -} diff --git a/terraform/test-fixtures/transform-provider-missing/main.tf b/terraform/test-fixtures/transform-provider-missing/main.tf new file mode 100644 index 000000000..976f3e5af --- /dev/null +++ b/terraform/test-fixtures/transform-provider-missing/main.tf @@ -0,0 +1,3 @@ +provider "aws" {} +resource "aws_instance" "web" {} +resource "foo_instance" "web" {} diff --git a/terraform/transform_provider.go b/terraform/transform_provider.go index cadfa12be..ad0a5f2e3 100644 --- a/terraform/transform_provider.go +++ b/terraform/transform_provider.go @@ -2,6 +2,7 @@ package terraform import ( "fmt" + "strings" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/config" @@ -146,15 +147,44 @@ type MissingProviderTransformer struct { } func (t *MissingProviderTransformer) Transform(g *Graph) error { + // Create a set of our supported providers + supported := make(map[string]struct{}, len(t.Providers)) + for _, v := range t.Providers { + supported[v] = struct{}{} + } + + // Get the map of providers we already have in our graph m := providerVertexMap(g) - for _, p := range t.Providers { - if _, ok := m[p]; ok { - // This provider already exists as a configured node + + // Go through all the provider consumers and make sure we add + // that provider if it is missing. + for _, v := range g.Vertices() { + pv, ok := v.(GraphNodeProviderConsumer) + if !ok { continue } - // Add our own missing provider node to the graph - g.Add(&graphNodeMissingProvider{ProviderNameValue: p}) + for _, p := range pv.ProvidedBy() { + if _, ok := m[p]; ok { + // This provider already exists as a configure node + break + } + + // If the provider has an alias in it, we just want the type + ptype := p + if idx := strings.IndexRune(p, '.'); idx != -1 { + ptype = p[:idx] + } + + if _, ok := supported[ptype]; !ok { + // If we don't support the provider type, skip it. + // Validation later will catch this as an error. + continue + } + + // Add our own missing provider node to the graph + m[p] = g.Add(&graphNodeMissingProvider{ProviderNameValue: p}) + } } return nil diff --git a/terraform/transform_provider_test.go b/terraform/transform_provider_test.go index 63ddfba0e..880c24637 100644 --- a/terraform/transform_provider_test.go +++ b/terraform/transform_provider_test.go @@ -63,7 +63,7 @@ func TestCloseProviderTransformer(t *testing.T) { } func TestMissingProviderTransformer(t *testing.T) { - mod := testModule(t, "transform-provider-basic") + mod := testModule(t, "transform-provider-missing") g := Graph{Path: RootModulePath} { @@ -74,7 +74,7 @@ func TestMissingProviderTransformer(t *testing.T) { } { - transform := &MissingProviderTransformer{Providers: []string{"foo"}} + transform := &MissingProviderTransformer{Providers: []string{"foo", "bar"}} if err := transform.Transform(&g); err != nil { t.Fatalf("err: %s", err) } @@ -275,10 +275,13 @@ provider.aws (close) const testTransformMissingProviderBasicStr = ` aws_instance.web +foo_instance.web provider.aws provider.aws (close) aws_instance.web provider.foo +provider.foo (close) + foo_instance.web ` const testTransformPruneProviderBasicStr = `