mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #16540 from hashicorp/jbardin/provider-inheritance
New provider inheritance
This commit is contained in:
commit
89b931e18a
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/copy"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,14 +58,10 @@ func TestGet_multipleArgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGet_noArgs(t *testing.T) {
|
func TestGet_noArgs(t *testing.T) {
|
||||||
cwd, err := os.Getwd()
|
td := tempDir(t)
|
||||||
if err != nil {
|
copy.CopyDir(testFixturePath("get"), td)
|
||||||
t.Fatalf("err: %s", err)
|
defer os.RemoveAll(td)
|
||||||
}
|
defer testChdir(t, td)()
|
||||||
if err := os.Chdir(testFixturePath("get")); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
defer os.Chdir(cwd)
|
|
||||||
|
|
||||||
ui := new(cli.MockUi)
|
ui := new(cli.MockUi)
|
||||||
c := &GetCommand{
|
c := &GetCommand{
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
resource "bar_resource" "in_grandchild" {}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
resource "foo_resource" "in_child" {}
|
|
||||||
|
|
||||||
provider "bar" {
|
|
||||||
value = "from child"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "grandchild" {
|
|
||||||
source = "./grandchild"
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
provider "foo" {
|
|
||||||
value = "from root"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "child" {
|
|
||||||
source = "./child"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
resource "foo_instance" "bar" {}
|
|
@ -1,7 +0,0 @@
|
|||||||
provider "foo" {
|
|
||||||
value = "from root"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "child" {
|
|
||||||
source = "./child"
|
|
||||||
}
|
|
@ -365,50 +365,6 @@ func (t *Tree) inheritProviderConfigs(stack []*Tree) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for implicit provider configs
|
|
||||||
// This adds an empty config is no inherited config is found, so that
|
|
||||||
// there is always a provider config present.
|
|
||||||
// This is done in the root module as well, just to set the providers.
|
|
||||||
for missing := range missingProviders {
|
|
||||||
// first create an empty provider config
|
|
||||||
pc := &config.ProviderConfig{
|
|
||||||
Name: missing,
|
|
||||||
}
|
|
||||||
|
|
||||||
// walk up the stack looking for matching providers
|
|
||||||
for i := len(stack) - 2; i >= 0; i-- {
|
|
||||||
pt := stack[i]
|
|
||||||
var parentProvider *config.ProviderConfig
|
|
||||||
for _, p := range pt.config.ProviderConfigs {
|
|
||||||
if p.FullName() == missing {
|
|
||||||
parentProvider = p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if parentProvider == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pc.Path = pt.Path()
|
|
||||||
pc.Path = append([]string{RootName}, pt.path...)
|
|
||||||
pc.RawConfig = parentProvider.RawConfig
|
|
||||||
pc.Inherited = true
|
|
||||||
log.Printf("[TRACE] provider %q inheriting config from %q",
|
|
||||||
strings.Join(append(t.Path(), pc.FullName()), "."),
|
|
||||||
strings.Join(append(pt.Path(), parentProvider.FullName()), "."),
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// always set a provider config
|
|
||||||
if pc.RawConfig == nil {
|
|
||||||
pc.RawConfig, _ = config.NewRawConfig(map[string]interface{}{})
|
|
||||||
}
|
|
||||||
|
|
||||||
t.config.ProviderConfigs = append(t.config.ProviderConfigs, pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// After allowing the empty implicit configs to be created in root, there's nothing left to inherit
|
// After allowing the empty implicit configs to be created in root, there's nothing left to inherit
|
||||||
if len(stack) == 1 {
|
if len(stack) == 1 {
|
||||||
return
|
return
|
||||||
|
@ -611,117 +611,6 @@ func TestTreeProviders_basic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTreeProviders_implicit(t *testing.T) {
|
|
||||||
storage := testStorage(t, nil)
|
|
||||||
tree := NewTree("", testConfig(t, "implicit-parent-providers"))
|
|
||||||
|
|
||||||
storage.Mode = GetModeGet
|
|
||||||
if err := tree.Load(storage); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var child *Tree
|
|
||||||
for _, c := range tree.Children() {
|
|
||||||
if c.Name() == "child" {
|
|
||||||
child = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if child == nil {
|
|
||||||
t.Fatal("could not find module 'child'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// child should have inherited foo
|
|
||||||
providers := child.config.ProviderConfigsByFullName()
|
|
||||||
foo := providers["foo"]
|
|
||||||
|
|
||||||
if foo == nil {
|
|
||||||
t.Fatal("could not find provider 'foo' in child module")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual([]string{RootName}, foo.Path) {
|
|
||||||
t.Fatalf(`expected foo scope of {"root"}, got %#v`, foo.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
|
||||||
"value": "from root",
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(expected, foo.RawConfig.RawMap()) {
|
|
||||||
t.Fatalf(`expected "foo" config %#v, got: %#v`, expected, foo.RawConfig.RawMap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTreeProviders_implicitMultiLevel(t *testing.T) {
|
|
||||||
storage := testStorage(t, nil)
|
|
||||||
tree := NewTree("", testConfig(t, "implicit-grandparent-providers"))
|
|
||||||
|
|
||||||
storage.Mode = GetModeGet
|
|
||||||
if err := tree.Load(storage); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var child, grandchild *Tree
|
|
||||||
for _, c := range tree.Children() {
|
|
||||||
if c.Name() == "child" {
|
|
||||||
child = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if child == nil {
|
|
||||||
t.Fatal("could not find module 'child'")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range child.Children() {
|
|
||||||
if c.Name() == "grandchild" {
|
|
||||||
grandchild = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if grandchild == nil {
|
|
||||||
t.Fatal("could not find module 'grandchild'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// child should have inherited foo
|
|
||||||
providers := child.config.ProviderConfigsByFullName()
|
|
||||||
foo := providers["foo"]
|
|
||||||
|
|
||||||
if foo == nil {
|
|
||||||
t.Fatal("could not find provider 'foo' in child module")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual([]string{RootName}, foo.Path) {
|
|
||||||
t.Fatalf(`expected foo scope of {"root"}, got %#v`, foo.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
|
||||||
"value": "from root",
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(expected, foo.RawConfig.RawMap()) {
|
|
||||||
t.Fatalf(`expected "foo" config %#v, got: %#v`, expected, foo.RawConfig.RawMap())
|
|
||||||
}
|
|
||||||
|
|
||||||
// grandchild should have inherited bar
|
|
||||||
providers = grandchild.config.ProviderConfigsByFullName()
|
|
||||||
bar := providers["bar"]
|
|
||||||
|
|
||||||
if bar == nil {
|
|
||||||
t.Fatal("could not find provider 'bar' in grandchild module")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual([]string{RootName, "child"}, bar.Path) {
|
|
||||||
t.Fatalf(`expected bar scope of {"root", "child"}, got %#v`, bar.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = map[string]interface{}{
|
|
||||||
"value": "from child",
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(expected, bar.RawConfig.RawMap()) {
|
|
||||||
t.Fatalf(`expected "bar" config %#v, got: %#v`, expected, bar.RawConfig.RawMap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTreeLoad_conflictingSubmoduleNames(t *testing.T) {
|
func TestTreeLoad_conflictingSubmoduleNames(t *testing.T) {
|
||||||
storage := testStorage(t, nil)
|
storage := testStorage(t, nil)
|
||||||
tree := NewTree("", testConfig(t, "conficting-submodule-names"))
|
tree := NewTree("", testConfig(t, "conficting-submodule-names"))
|
||||||
|
@ -861,7 +861,7 @@ func TestContext2Apply_createBeforeDestroy(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(state.String())
|
actual := strings.TrimSpace(state.String())
|
||||||
expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
|
expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad: \n%s", actual)
|
t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2639,107 +2639,105 @@ module.child:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
//// FIXME: how do we handle this one?
|
func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
|
||||||
//func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
|
m := testModule(t, "apply-module-orphan-provider-inherit")
|
||||||
// m := testModule(t, "apply-module-orphan-provider-inherit")
|
p := testProvider("aws")
|
||||||
// p := testProvider("aws")
|
p.ApplyFn = testApplyFn
|
||||||
// p.ApplyFn = testApplyFn
|
p.DiffFn = testDiffFn
|
||||||
// p.DiffFn = testDiffFn
|
|
||||||
|
|
||||||
// p.ConfigureFn = func(c *ResourceConfig) error {
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
||||||
// if _, ok := c.Get("value"); !ok {
|
if _, ok := c.Get("value"); !ok {
|
||||||
// return fmt.Errorf("value is not found")
|
return fmt.Errorf("value is not found")
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return nil
|
return nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Create a state with an orphan module
|
// Create a state with an orphan module
|
||||||
// state := &State{
|
state := &State{
|
||||||
// Modules: []*ModuleState{
|
Modules: []*ModuleState{
|
||||||
// &ModuleState{
|
&ModuleState{
|
||||||
// Path: []string{"root", "child"},
|
Path: []string{"root", "child"},
|
||||||
// Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
// "aws_instance.bar": &ResourceState{
|
"aws_instance.bar": &ResourceState{
|
||||||
// Type: "aws_instance",
|
Type: "aws_instance",
|
||||||
// Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
// ID: "bar",
|
ID: "bar",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
|
|
||||||
// ctx := testContext2(t, &ContextOpts{
|
ctx := testContext2(t, &ContextOpts{
|
||||||
// Module: m,
|
Module: m,
|
||||||
// State: state,
|
State: state,
|
||||||
// ProviderResolver: ResourceProviderResolverFixed(
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
// map[string]ResourceProviderFactory{
|
map[string]ResourceProviderFactory{
|
||||||
// "aws": testProviderFuncFixed(p),
|
"aws": testProviderFuncFixed(p),
|
||||||
// },
|
},
|
||||||
// ),
|
),
|
||||||
// })
|
})
|
||||||
|
|
||||||
// if _, err := ctx.Plan(); err != nil {
|
if _, err := ctx.Plan(); err != nil {
|
||||||
// t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if _, err := ctx.Apply(); err != nil {
|
if _, err := ctx.Apply(); err != nil {
|
||||||
// t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
//// FIXME: how do we handle this one?
|
func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
|
||||||
//func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
|
m := testModule(t, "apply-module-orphan-provider-inherit")
|
||||||
// m := testModule(t, "apply-module-orphan-provider-inherit")
|
p := testProvider("aws")
|
||||||
// p := testProvider("aws")
|
p.ApplyFn = testApplyFn
|
||||||
// p.ApplyFn = testApplyFn
|
p.DiffFn = testDiffFn
|
||||||
// p.DiffFn = testDiffFn
|
|
||||||
|
|
||||||
// p.ConfigureFn = func(c *ResourceConfig) error {
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
||||||
// if _, ok := c.Get("value"); !ok {
|
if _, ok := c.Get("value"); !ok {
|
||||||
// return fmt.Errorf("value is not found")
|
return fmt.Errorf("value is not found")
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return nil
|
return nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Create a state with an orphan module that is nested (grandchild)
|
// Create a state with an orphan module that is nested (grandchild)
|
||||||
// state := &State{
|
state := &State{
|
||||||
// Modules: []*ModuleState{
|
Modules: []*ModuleState{
|
||||||
// &ModuleState{
|
&ModuleState{
|
||||||
// Path: []string{"root", "parent", "child"},
|
Path: []string{"root", "parent", "child"},
|
||||||
// Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
// "aws_instance.bar": &ResourceState{
|
"aws_instance.bar": &ResourceState{
|
||||||
// Type: "aws_instance",
|
Type: "aws_instance",
|
||||||
// Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
// ID: "bar",
|
ID: "bar",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
|
|
||||||
// ctx := testContext2(t, &ContextOpts{
|
ctx := testContext2(t, &ContextOpts{
|
||||||
// Module: m,
|
Module: m,
|
||||||
// State: state,
|
State: state,
|
||||||
// ProviderResolver: ResourceProviderResolverFixed(
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
// map[string]ResourceProviderFactory{
|
map[string]ResourceProviderFactory{
|
||||||
// "aws": testProviderFuncFixed(p),
|
"aws": testProviderFuncFixed(p),
|
||||||
// },
|
},
|
||||||
// ),
|
),
|
||||||
// })
|
})
|
||||||
|
|
||||||
// if _, err := ctx.Plan(); err != nil {
|
if _, err := ctx.Plan(); err != nil {
|
||||||
// t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if _, err := ctx.Apply(); err != nil {
|
if _, err := ctx.Apply(); err != nil {
|
||||||
// t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
|
func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
|
||||||
m := testModule(t, "apply-module-grandchild-provider-inherit")
|
m := testModule(t, "apply-module-grandchild-provider-inherit")
|
||||||
|
@ -687,13 +687,10 @@ func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"root\n",
|
|
||||||
// this test originally verified that a parent provider config can
|
|
||||||
// partially override a child. That's no longer the case, so the child
|
|
||||||
// config is used in its entirety here.
|
|
||||||
//"root\nchild\n",
|
|
||||||
"child\nchild\n",
|
"child\nchild\n",
|
||||||
|
"root\n",
|
||||||
}
|
}
|
||||||
|
sort.Strings(calls)
|
||||||
if !reflect.DeepEqual(calls, expected) {
|
if !reflect.DeepEqual(calls, expected) {
|
||||||
t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls)
|
t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls)
|
||||||
}
|
}
|
||||||
|
@ -321,55 +321,53 @@ func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// FIXME: provider must still exist in config, but we should be able to locate
|
func TestContext2Validate_moduleProviderInheritOrphan(t *testing.T) {
|
||||||
//// it elsewhere
|
m := testModule(t, "validate-module-pc-inherit-orphan")
|
||||||
//func TestContext2Validate_moduleProviderInheritOrphan(t *testing.T) {
|
p := testProvider("aws")
|
||||||
// m := testModule(t, "validate-module-pc-inherit-orphan")
|
c := testContext2(t, &ContextOpts{
|
||||||
// p := testProvider("aws")
|
Module: m,
|
||||||
// c := testContext2(t, &ContextOpts{
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
// Module: m,
|
map[string]ResourceProviderFactory{
|
||||||
// ProviderResolver: ResourceProviderResolverFixed(
|
"aws": testProviderFuncFixed(p),
|
||||||
// map[string]ResourceProviderFactory{
|
},
|
||||||
// "aws": testProviderFuncFixed(p),
|
),
|
||||||
// },
|
State: &State{
|
||||||
// ),
|
Modules: []*ModuleState{
|
||||||
// State: &State{
|
&ModuleState{
|
||||||
// Modules: []*ModuleState{
|
Path: []string{"root", "child"},
|
||||||
// &ModuleState{
|
Resources: map[string]*ResourceState{
|
||||||
// Path: []string{"root", "child"},
|
"aws_instance.bar": &ResourceState{
|
||||||
// Resources: map[string]*ResourceState{
|
Type: "aws_instance",
|
||||||
// "aws_instance.bar": &ResourceState{
|
Primary: &InstanceState{
|
||||||
// Type: "aws_instance",
|
ID: "bar",
|
||||||
// Primary: &InstanceState{
|
},
|
||||||
// ID: "bar",
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
})
|
||||||
// },
|
|
||||||
// })
|
|
||||||
|
|
||||||
// p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
||||||
// v, ok := c.Get("set")
|
v, ok := c.Get("set")
|
||||||
// if !ok {
|
if !ok {
|
||||||
// return nil, []error{fmt.Errorf("not set")}
|
return nil, []error{fmt.Errorf("not set")}
|
||||||
// }
|
}
|
||||||
// if v != "bar" {
|
if v != "bar" {
|
||||||
// return nil, []error{fmt.Errorf("bad: %#v", v)}
|
return nil, []error{fmt.Errorf("bad: %#v", v)}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return nil, nil
|
return nil, nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// w, e := c.Validate()
|
w, e := c.Validate()
|
||||||
// if len(w) > 0 {
|
if len(w) > 0 {
|
||||||
// t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", w)
|
||||||
// }
|
}
|
||||||
// if len(e) > 0 {
|
if len(e) > 0 {
|
||||||
// t.Fatalf("bad: %s", e)
|
t.Fatalf("bad: %s", e)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
func TestContext2Validate_moduleProviderVar(t *testing.T) {
|
func TestContext2Validate_moduleProviderVar(t *testing.T) {
|
||||||
m := testModule(t, "validate-module-pc-vars")
|
m := testModule(t, "validate-module-pc-vars")
|
||||||
|
@ -22,11 +22,11 @@ type EvalContext interface {
|
|||||||
// Input is the UIInput object for interacting with the UI.
|
// Input is the UIInput object for interacting with the UI.
|
||||||
Input() UIInput
|
Input() UIInput
|
||||||
|
|
||||||
// InitProvider initializes the provider with the given name and
|
// InitProvider initializes the provider with the given type and name, and
|
||||||
// returns the implementation of the resource provider or an error.
|
// returns the implementation of the resource provider or an error.
|
||||||
//
|
//
|
||||||
// It is an error to initialize the same provider more than once.
|
// It is an error to initialize the same provider more than once.
|
||||||
InitProvider(string) (ResourceProvider, error)
|
InitProvider(typ string, name string) (ResourceProvider, error)
|
||||||
|
|
||||||
// Provider gets the provider instance with the given name (already
|
// Provider gets the provider instance with the given name (already
|
||||||
// initialized) or returns nil if the provider isn't initialized.
|
// initialized) or returns nil if the provider isn't initialized.
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
@ -79,12 +78,12 @@ func (ctx *BuiltinEvalContext) Input() UIInput {
|
|||||||
return ctx.InputValue
|
return ctx.InputValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProvider, error) {
|
||||||
ctx.once.Do(ctx.init)
|
ctx.once.Do(ctx.init)
|
||||||
|
|
||||||
// If we already initialized, it is an error
|
// If we already initialized, it is an error
|
||||||
if p := ctx.Provider(n); p != nil {
|
if p := ctx.Provider(name); p != nil {
|
||||||
return nil, fmt.Errorf("Provider '%s' already initialized", n)
|
return nil, fmt.Errorf("Provider '%s' already initialized", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning: make sure to acquire these locks AFTER the call to Provider
|
// Warning: make sure to acquire these locks AFTER the call to Provider
|
||||||
@ -92,18 +91,12 @@ func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error)
|
|||||||
ctx.ProviderLock.Lock()
|
ctx.ProviderLock.Lock()
|
||||||
defer ctx.ProviderLock.Unlock()
|
defer ctx.ProviderLock.Unlock()
|
||||||
|
|
||||||
providerPath := make([]string, len(ctx.Path())+1)
|
p, err := ctx.Components.ResourceProvider(typeName, name)
|
||||||
copy(providerPath, ctx.Path())
|
|
||||||
providerPath[len(providerPath)-1] = n
|
|
||||||
key := PathCacheKey(providerPath)
|
|
||||||
|
|
||||||
typeName := strings.SplitN(n, ".", 2)[0]
|
|
||||||
p, err := ctx.Components.ResourceProvider(typeName, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ProviderCache[key] = p
|
ctx.ProviderCache[name] = p
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,11 +106,7 @@ func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
|
|||||||
ctx.ProviderLock.Lock()
|
ctx.ProviderLock.Lock()
|
||||||
defer ctx.ProviderLock.Unlock()
|
defer ctx.ProviderLock.Unlock()
|
||||||
|
|
||||||
providerPath := make([]string, len(ctx.Path())+1)
|
return ctx.ProviderCache[n]
|
||||||
copy(providerPath, ctx.Path())
|
|
||||||
providerPath[len(providerPath)-1] = n
|
|
||||||
|
|
||||||
return ctx.ProviderCache[PathCacheKey(providerPath)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) CloseProvider(n string) error {
|
func (ctx *BuiltinEvalContext) CloseProvider(n string) error {
|
||||||
@ -126,15 +115,11 @@ func (ctx *BuiltinEvalContext) CloseProvider(n string) error {
|
|||||||
ctx.ProviderLock.Lock()
|
ctx.ProviderLock.Lock()
|
||||||
defer ctx.ProviderLock.Unlock()
|
defer ctx.ProviderLock.Unlock()
|
||||||
|
|
||||||
providerPath := make([]string, len(ctx.Path())+1)
|
|
||||||
copy(providerPath, ctx.Path())
|
|
||||||
providerPath[len(providerPath)-1] = n
|
|
||||||
|
|
||||||
var provider interface{}
|
var provider interface{}
|
||||||
provider = ctx.ProviderCache[PathCacheKey(providerPath)]
|
provider = ctx.ProviderCache[n]
|
||||||
if provider != nil {
|
if provider != nil {
|
||||||
if p, ok := provider.(ResourceProviderCloser); ok {
|
if p, ok := provider.(ResourceProviderCloser); ok {
|
||||||
delete(ctx.ProviderCache, PathCacheKey(providerPath))
|
delete(ctx.ProviderCache, n)
|
||||||
return p.Close()
|
return p.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (c *MockEvalContext) Input() UIInput {
|
|||||||
return c.InputInput
|
return c.InputInput
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
func (c *MockEvalContext) InitProvider(t, n string) (ResourceProvider, error) {
|
||||||
c.InitProviderCalled = true
|
c.InitProviderCalled = true
|
||||||
c.InitProviderName = n
|
c.InitProviderName = n
|
||||||
return c.InitProviderProvider, c.InitProviderError
|
return c.InitProviderProvider, c.InitProviderError
|
||||||
|
@ -52,11 +52,12 @@ func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
// and returns nothing. The provider can be retrieved again with the
|
// and returns nothing. The provider can be retrieved again with the
|
||||||
// EvalGetProvider node.
|
// EvalGetProvider node.
|
||||||
type EvalInitProvider struct {
|
type EvalInitProvider struct {
|
||||||
Name string
|
TypeName string
|
||||||
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
|
func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
return ctx.InitProvider(n.Name)
|
return ctx.InitProvider(n.TypeName, n.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvalCloseProvider is an EvalNode implementation that closes provider
|
// EvalCloseProvider is an EvalNode implementation that closes provider
|
||||||
@ -129,6 +130,7 @@ func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetProviderInput(n.Name, confMap)
|
ctx.SetProviderInput(n.Name, confMap)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProviderEvalTree returns the evaluation tree for initializing and
|
// ProviderEvalTree returns the evaluation tree for initializing and
|
||||||
// configuring providers.
|
// configuring providers.
|
||||||
func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
func ProviderEvalTree(n *NodeApplyableProvider, config *config.ProviderConfig) EvalNode {
|
||||||
var provider ResourceProvider
|
var provider ResourceProvider
|
||||||
var resourceConfig *ResourceConfig
|
var resourceConfig *ResourceConfig
|
||||||
|
|
||||||
|
typeName := strings.SplitN(n.NameValue, ".", 2)[0]
|
||||||
|
|
||||||
seq := make([]EvalNode, 0, 5)
|
seq := make([]EvalNode, 0, 5)
|
||||||
seq = append(seq, &EvalInitProvider{Name: n})
|
seq = append(seq, &EvalInitProvider{
|
||||||
|
TypeName: typeName,
|
||||||
|
Name: n.Name(),
|
||||||
|
})
|
||||||
|
|
||||||
// Input stuff
|
// Input stuff
|
||||||
seq = append(seq, &EvalOpFilter{
|
seq = append(seq, &EvalOpFilter{
|
||||||
@ -19,7 +26,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n,
|
Name: n.Name(),
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalInterpolateProvider{
|
&EvalInterpolateProvider{
|
||||||
@ -27,12 +34,12 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalBuildProviderConfig{
|
&EvalBuildProviderConfig{
|
||||||
Provider: n,
|
Provider: n.NameValue,
|
||||||
Config: &resourceConfig,
|
Config: &resourceConfig,
|
||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalInputProvider{
|
&EvalInputProvider{
|
||||||
Name: n,
|
Name: n.NameValue,
|
||||||
Provider: &provider,
|
Provider: &provider,
|
||||||
Config: &resourceConfig,
|
Config: &resourceConfig,
|
||||||
},
|
},
|
||||||
@ -45,7 +52,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n,
|
Name: n.Name(),
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalInterpolateProvider{
|
&EvalInterpolateProvider{
|
||||||
@ -53,7 +60,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalBuildProviderConfig{
|
&EvalBuildProviderConfig{
|
||||||
Provider: n,
|
Provider: n.NameValue,
|
||||||
Config: &resourceConfig,
|
Config: &resourceConfig,
|
||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
@ -71,7 +78,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n,
|
Name: n.Name(),
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalInterpolateProvider{
|
&EvalInterpolateProvider{
|
||||||
@ -79,7 +86,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalBuildProviderConfig{
|
&EvalBuildProviderConfig{
|
||||||
Provider: n,
|
Provider: n.NameValue,
|
||||||
Config: &resourceConfig,
|
Config: &resourceConfig,
|
||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
@ -94,7 +101,7 @@ func ProviderEvalTree(n string, config *config.ProviderConfig) EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalConfigProvider{
|
&EvalConfigProvider{
|
||||||
Provider: n,
|
Provider: n.Name(),
|
||||||
Config: &resourceConfig,
|
Config: &resourceConfig,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -87,12 +87,8 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// Attach the state
|
// Attach the state
|
||||||
&AttachStateTransformer{State: b.State},
|
&AttachStateTransformer{State: b.State},
|
||||||
|
|
||||||
// Create all the providers
|
// add providers
|
||||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
|
TransformProviders(b.Providers, concreteProvider, b.Module),
|
||||||
&ProviderTransformer{},
|
|
||||||
&DisableProviderTransformer{},
|
|
||||||
&ParentProviderTransformer{},
|
|
||||||
&AttachProviderConfigTransformer{Module: b.Module},
|
|
||||||
|
|
||||||
// Destruction ordering
|
// Destruction ordering
|
||||||
&DestroyEdgeTransformer{Module: b.Module, State: b.State},
|
&DestroyEdgeTransformer{Module: b.Module, State: b.State},
|
||||||
|
@ -84,7 +84,7 @@ func TestApplyGraphBuilder(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testApplyGraphBuilderStr)
|
expected := strings.TrimSpace(testApplyGraphBuilderStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad: %s", actual)
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,16 +497,13 @@ meta.count-boundary (count boundary fixup)
|
|||||||
aws_instance.other
|
aws_instance.other
|
||||||
module.child.aws_instance.create
|
module.child.aws_instance.create
|
||||||
module.child.aws_instance.other
|
module.child.aws_instance.other
|
||||||
module.child.provider.aws
|
|
||||||
module.child.provisioner.exec
|
module.child.provisioner.exec
|
||||||
provider.aws
|
provider.aws
|
||||||
module.child.aws_instance.create
|
module.child.aws_instance.create
|
||||||
module.child.provider.aws
|
|
||||||
module.child.provisioner.exec
|
module.child.provisioner.exec
|
||||||
|
provider.aws
|
||||||
module.child.aws_instance.other
|
module.child.aws_instance.other
|
||||||
module.child.aws_instance.create
|
module.child.aws_instance.create
|
||||||
module.child.provider.aws
|
|
||||||
module.child.provider.aws
|
|
||||||
provider.aws
|
provider.aws
|
||||||
module.child.provisioner.exec
|
module.child.provisioner.exec
|
||||||
provider.aws
|
provider.aws
|
||||||
|
@ -52,12 +52,7 @@ func (b *ImportGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// Add the import steps
|
// Add the import steps
|
||||||
&ImportStateTransformer{Targets: b.ImportTargets},
|
&ImportStateTransformer{Targets: b.ImportTargets},
|
||||||
|
|
||||||
// Provider-related transformations
|
TransformProviders(b.Providers, concreteProvider, mod),
|
||||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
|
|
||||||
&ProviderTransformer{},
|
|
||||||
&DisableProviderTransformer{},
|
|
||||||
&ParentProviderTransformer{},
|
|
||||||
&AttachProviderConfigTransformer{Module: mod},
|
|
||||||
|
|
||||||
// This validates that the providers only depend on variables
|
// This validates that the providers only depend on variables
|
||||||
&ImportProviderValidateTransformer{},
|
&ImportProviderValidateTransformer{},
|
||||||
|
@ -93,12 +93,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// Add root variables
|
// Add root variables
|
||||||
&RootVariableTransformer{Module: b.Module},
|
&RootVariableTransformer{Module: b.Module},
|
||||||
|
|
||||||
// Create all the providers
|
TransformProviders(b.Providers, b.ConcreteProvider, b.Module),
|
||||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: b.ConcreteProvider},
|
|
||||||
&ProviderTransformer{},
|
|
||||||
&DisableProviderTransformer{},
|
|
||||||
&ParentProviderTransformer{},
|
|
||||||
&AttachProviderConfigTransformer{Module: b.Module},
|
|
||||||
|
|
||||||
// Provisioner-related transformations. Only add these if requested.
|
// Provisioner-related transformations. Only add these if requested.
|
||||||
GraphTransformIf(
|
GraphTransformIf(
|
||||||
|
@ -126,12 +126,7 @@ func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// Add root variables
|
// Add root variables
|
||||||
&RootVariableTransformer{Module: b.Module},
|
&RootVariableTransformer{Module: b.Module},
|
||||||
|
|
||||||
// Create all the providers
|
TransformProviders(b.Providers, concreteProvider, b.Module),
|
||||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
|
|
||||||
&ProviderTransformer{},
|
|
||||||
&DisableProviderTransformer{},
|
|
||||||
&ParentProviderTransformer{},
|
|
||||||
&AttachProviderConfigTransformer{Module: b.Module},
|
|
||||||
|
|
||||||
// Add the local values
|
// Add the local values
|
||||||
&LocalTransformer{Module: b.Module},
|
&LocalTransformer{Module: b.Module},
|
||||||
|
@ -73,8 +73,7 @@ func TestModuleTreeDependencies(t *testing.T) {
|
|||||||
Providers: moduledeps.Providers{
|
Providers: moduledeps.Providers{
|
||||||
"foo": moduledeps.ProviderDependency{
|
"foo": moduledeps.ProviderDependency{
|
||||||
Constraints: discovery.AllVersions,
|
Constraints: discovery.AllVersions,
|
||||||
//Reason: moduledeps.ProviderDependencyImplicit,
|
Reason: moduledeps.ProviderDependencyImplicit,
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
|
||||||
},
|
},
|
||||||
"foo.baz": moduledeps.ProviderDependency{
|
"foo.baz": moduledeps.ProviderDependency{
|
||||||
Constraints: discovery.AllVersions,
|
Constraints: discovery.AllVersions,
|
||||||
@ -119,28 +118,25 @@ func TestModuleTreeDependencies(t *testing.T) {
|
|||||||
Providers: moduledeps.Providers{
|
Providers: moduledeps.Providers{
|
||||||
"foo": moduledeps.ProviderDependency{
|
"foo": moduledeps.ProviderDependency{
|
||||||
Constraints: discovery.AllVersions,
|
Constraints: discovery.AllVersions,
|
||||||
//Reason: moduledeps.ProviderDependencyInherited,
|
Reason: moduledeps.ProviderDependencyInherited,
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
|
||||||
},
|
},
|
||||||
"baz": moduledeps.ProviderDependency{
|
"baz": moduledeps.ProviderDependency{
|
||||||
Constraints: discovery.AllVersions,
|
Constraints: discovery.AllVersions,
|
||||||
//Reason: moduledeps.ProviderDependencyImplicit,
|
Reason: moduledeps.ProviderDependencyImplicit,
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Children: []*moduledeps.Module{
|
Children: []*moduledeps.Module{
|
||||||
{
|
{
|
||||||
Name: "grandchild",
|
Name: "grandchild",
|
||||||
Providers: moduledeps.Providers{
|
Providers: moduledeps.Providers{
|
||||||
|
"bar": moduledeps.ProviderDependency{
|
||||||
|
Constraints: discovery.AllVersions,
|
||||||
|
Reason: moduledeps.ProviderDependencyInherited,
|
||||||
|
},
|
||||||
"foo": moduledeps.ProviderDependency{
|
"foo": moduledeps.ProviderDependency{
|
||||||
Constraints: discovery.AllVersions,
|
Constraints: discovery.AllVersions,
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
Reason: moduledeps.ProviderDependencyExplicit,
|
||||||
},
|
},
|
||||||
"bar": moduledeps.ProviderDependency{
|
|
||||||
Constraints: discovery.AllVersions,
|
|
||||||
//Reason: moduledeps.ProviderDependencyInherited,
|
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -27,6 +27,7 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
|
|||||||
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
||||||
// Add the config and state since we don't do that via transforms
|
// Add the config and state since we don't do that via transforms
|
||||||
a.Config = n.Config
|
a.Config = n.Config
|
||||||
|
a.ResolvedProvider = n.ResolvedProvider
|
||||||
|
|
||||||
return &NodeRefreshableDataResourceInstance{
|
return &NodeRefreshableDataResourceInstance{
|
||||||
NodeAbstractResource: a,
|
NodeAbstractResource: a,
|
||||||
@ -185,7 +186,7 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
|
|||||||
// provider configurations that need this data during
|
// provider configurations that need this data during
|
||||||
// refresh/plan.
|
// refresh/plan.
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -7,5 +7,5 @@ type NodeApplyableProvider struct {
|
|||||||
|
|
||||||
// GraphNodeEvalable
|
// GraphNodeEvalable
|
||||||
func (n *NodeApplyableProvider) EvalTree() EvalNode {
|
func (n *NodeApplyableProvider) EvalTree() EvalNode {
|
||||||
return ProviderEvalTree(n.NameValue, n.ProviderConfig())
|
return ProviderEvalTree(n, n.ProviderConfig())
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,17 @@ type NodeAbstractProvider struct {
|
|||||||
Config *config.ProviderConfig
|
Config *config.ProviderConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeAbstractProvider) Name() string {
|
func ResolveProviderName(name string, path []string) string {
|
||||||
result := fmt.Sprintf("provider.%s", n.NameValue)
|
name = fmt.Sprintf("provider.%s", name)
|
||||||
if len(n.PathValue) > 1 {
|
if len(path) > 1 {
|
||||||
result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result)
|
name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodeAbstractProvider) Name() string {
|
||||||
|
return ResolveProviderName(n.NameValue, n.PathValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeSubPath
|
// GraphNodeSubPath
|
||||||
|
@ -33,6 +33,9 @@ type NodeAbstractResource struct {
|
|||||||
ResourceState *ResourceState // ResourceState is the ResourceState for this
|
ResourceState *ResourceState // ResourceState is the ResourceState for this
|
||||||
|
|
||||||
Targets []ResourceAddress // Set from GraphNodeTargetable
|
Targets []ResourceAddress // Set from GraphNodeTargetable
|
||||||
|
|
||||||
|
// The address of the provider this resource will use
|
||||||
|
ResolvedProvider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeAbstractResource) Name() string {
|
func (n *NodeAbstractResource) Name() string {
|
||||||
@ -170,6 +173,10 @@ func (n *NodeAbstractResource) StateReferences() []string {
|
|||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NodeAbstractResource) SetProvider(p string) {
|
||||||
|
n.ResolvedProvider = p
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *NodeAbstractResource) ProvidedBy() []string {
|
func (n *NodeAbstractResource) ProvidedBy() []string {
|
||||||
// If we have a config we prefer that above all else
|
// If we have a config we prefer that above all else
|
||||||
|
@ -135,7 +135,7 @@ func (n *NodeApplyableResource) evalTreeDataResource(
|
|||||||
},
|
},
|
||||||
|
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadState{
|
&EvalReadState{
|
||||||
@ -283,7 +283,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
|||||||
},
|
},
|
||||||
|
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadState{
|
&EvalReadState{
|
||||||
|
@ -102,8 +102,9 @@ func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||||||
|
|
||||||
// We want deposed resources in the state to be destroyed
|
// We want deposed resources in the state to be destroyed
|
||||||
steps = append(steps, &DeposedTransformer{
|
steps = append(steps, &DeposedTransformer{
|
||||||
State: state,
|
State: state,
|
||||||
View: n.Addr.stateId(),
|
View: n.Addr.stateId(),
|
||||||
|
ResolvedProvider: n.ResolvedProvider,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
@ -188,7 +189,7 @@ func (n *NodeDestroyResource) EvalTree() EvalNode {
|
|||||||
&EvalInstanceInfo{Info: info},
|
&EvalInstanceInfo{Info: info},
|
||||||
|
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadState{
|
&EvalReadState{
|
||||||
|
@ -27,6 +27,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||||||
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
||||||
// Add the config and state since we don't do that via transforms
|
// Add the config and state since we don't do that via transforms
|
||||||
a.Config = n.Config
|
a.Config = n.Config
|
||||||
|
a.ResolvedProvider = n.ResolvedProvider
|
||||||
|
|
||||||
return &NodePlannableResourceInstance{
|
return &NodePlannableResourceInstance{
|
||||||
NodeAbstractResource: a,
|
NodeAbstractResource: a,
|
||||||
@ -37,6 +38,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||||||
concreteResourceOrphan := func(a *NodeAbstractResource) dag.Vertex {
|
concreteResourceOrphan := func(a *NodeAbstractResource) dag.Vertex {
|
||||||
// Add the config and state since we don't do that via transforms
|
// Add the config and state since we don't do that via transforms
|
||||||
a.Config = n.Config
|
a.Config = n.Config
|
||||||
|
a.ResolvedProvider = n.ResolvedProvider
|
||||||
|
|
||||||
return &NodePlannableResourceOrphan{
|
return &NodePlannableResourceOrphan{
|
||||||
NodeAbstractResource: a,
|
NodeAbstractResource: a,
|
||||||
|
@ -97,7 +97,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource(
|
|||||||
},
|
},
|
||||||
|
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
// Re-run validation to catch any errors we missed, e.g. type
|
// Re-run validation to catch any errors we missed, e.g. type
|
||||||
|
@ -30,6 +30,7 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
|
|||||||
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
||||||
// Add the config and state since we don't do that via transforms
|
// Add the config and state since we don't do that via transforms
|
||||||
a.Config = n.Config
|
a.Config = n.Config
|
||||||
|
a.ResolvedProvider = n.ResolvedProvider
|
||||||
|
|
||||||
return &NodeRefreshableManagedResourceInstance{
|
return &NodeRefreshableManagedResourceInstance{
|
||||||
NodeAbstractResource: a,
|
NodeAbstractResource: a,
|
||||||
@ -149,7 +150,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN
|
|||||||
return &EvalSequence{
|
return &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadState{
|
&EvalReadState{
|
||||||
@ -220,7 +221,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState(
|
|||||||
Output: &resourceConfig,
|
Output: &resourceConfig,
|
||||||
},
|
},
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
// Re-run validation to catch any errors we missed, e.g. type
|
// Re-run validation to catch any errors we missed, e.g. type
|
||||||
|
@ -39,6 +39,7 @@ func (n *NodeValidatableResource) DynamicExpand(ctx EvalContext) (*Graph, error)
|
|||||||
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
||||||
// Add the config and state since we don't do that via transforms
|
// Add the config and state since we don't do that via transforms
|
||||||
a.Config = n.Config
|
a.Config = n.Config
|
||||||
|
a.ResolvedProvider = n.ResolvedProvider
|
||||||
|
|
||||||
return &NodeValidatableResourceInstance{
|
return &NodeValidatableResourceInstance{
|
||||||
NodeAbstractResource: a,
|
NodeAbstractResource: a,
|
||||||
@ -108,7 +109,7 @@ func (n *NodeValidatableResourceInstance) EvalTree() EvalNode {
|
|||||||
Config: &n.Config.RawConfig,
|
Config: &n.Config.RawConfig,
|
||||||
},
|
},
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalInterpolate{
|
&EvalInterpolate{
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
module "sub" {
|
||||||
|
source = "./sub"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
provider "foo" {}
|
||||||
|
|
||||||
|
module "subsub" {
|
||||||
|
source = "./subsub"
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
resource "foo_instance" "one" {}
|
||||||
|
resource "bar_instance" "two" {}
|
@ -1,6 +1,8 @@
|
|||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,6 +42,9 @@ func (t *graphTransformerMulti) Transform(g *Graph) error {
|
|||||||
if err := t.Transform(g); err != nil {
|
if err := t.Transform(g); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Printf(
|
||||||
|
"[TRACE] Graph after step %T:\n\n%s",
|
||||||
|
t, g.StringWithNodeTypes())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -133,3 +133,78 @@ func (t *ConfigTransformer) transformSingle(g *Graph, m *module.Tree) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProviderConfigTransformer struct {
|
||||||
|
Providers []string
|
||||||
|
Concrete ConcreteProviderNodeFunc
|
||||||
|
|
||||||
|
// Module is the module to add resources from.
|
||||||
|
Module *module.Tree
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProviderConfigTransformer) Transform(g *Graph) error {
|
||||||
|
// If no module is given, we don't do anything
|
||||||
|
if t.Module == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the module isn't loaded, that is simply an error
|
||||||
|
if !t.Module.Loaded() {
|
||||||
|
return errors.New("module must be loaded for ProviderConfigTransformer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the transformation process
|
||||||
|
return t.transform(g, t.Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProviderConfigTransformer) transform(g *Graph, m *module.Tree) error {
|
||||||
|
// If no config, do nothing
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add our resources
|
||||||
|
if err := t.transformSingle(g, m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform all the children.
|
||||||
|
for _, c := range m.Children() {
|
||||||
|
if err := t.transform(g, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) error {
|
||||||
|
log.Printf("[TRACE] ProviderConfigTransformer: Starting for path: %v", m.Path())
|
||||||
|
|
||||||
|
// Get the configuration for this module
|
||||||
|
conf := m.Config()
|
||||||
|
|
||||||
|
// Build the path we're at
|
||||||
|
path := m.Path()
|
||||||
|
if len(path) > 0 {
|
||||||
|
path = append([]string{RootModuleName}, path...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all the resources out
|
||||||
|
for _, p := range conf.ProviderConfigs {
|
||||||
|
name := p.Name
|
||||||
|
if p.Alias != "" {
|
||||||
|
name += "." + p.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
v := t.Concrete(&NodeAbstractProvider{
|
||||||
|
NameValue: name,
|
||||||
|
PathValue: path,
|
||||||
|
}).(dag.Vertex)
|
||||||
|
|
||||||
|
// Add it to the graph
|
||||||
|
g.Add(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -12,6 +12,9 @@ type DeposedTransformer struct {
|
|||||||
// View, if non-empty, is the ModuleState.View used around the state
|
// View, if non-empty, is the ModuleState.View used around the state
|
||||||
// to find deposed resources.
|
// to find deposed resources.
|
||||||
View string
|
View string
|
||||||
|
|
||||||
|
// The provider used by the resourced which were deposed
|
||||||
|
ResolvedProvider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DeposedTransformer) Transform(g *Graph) error {
|
func (t *DeposedTransformer) Transform(g *Graph) error {
|
||||||
@ -33,14 +36,16 @@ func (t *DeposedTransformer) Transform(g *Graph) error {
|
|||||||
if len(rs.Deposed) == 0 {
|
if len(rs.Deposed) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
deposed := rs.Deposed
|
deposed := rs.Deposed
|
||||||
|
|
||||||
for i, _ := range deposed {
|
for i, _ := range deposed {
|
||||||
g.Add(&graphNodeDeposedResource{
|
g.Add(&graphNodeDeposedResource{
|
||||||
Index: i,
|
Index: i,
|
||||||
ResourceName: k,
|
ResourceName: k,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
Provider: rs.Provider,
|
ProviderName: rs.Provider,
|
||||||
|
ResolvedProvider: t.ResolvedProvider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,10 +55,11 @@ func (t *DeposedTransformer) Transform(g *Graph) error {
|
|||||||
|
|
||||||
// graphNodeDeposedResource is the graph vertex representing a deposed resource.
|
// graphNodeDeposedResource is the graph vertex representing a deposed resource.
|
||||||
type graphNodeDeposedResource struct {
|
type graphNodeDeposedResource struct {
|
||||||
Index int
|
Index int
|
||||||
ResourceName string
|
ResourceName string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
Provider string
|
ProviderName string
|
||||||
|
ResolvedProvider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeDeposedResource) Name() string {
|
func (n *graphNodeDeposedResource) Name() string {
|
||||||
@ -61,7 +67,11 @@ func (n *graphNodeDeposedResource) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeDeposedResource) ProvidedBy() []string {
|
func (n *graphNodeDeposedResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.ResourceName, n.Provider)}
|
return []string{resourceProvider(n.ResourceName, n.ProviderName)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *graphNodeDeposedResource) SetProvider(p string) {
|
||||||
|
n.ResolvedProvider = p
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
@ -81,7 +91,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadStateDeposed{
|
&EvalReadStateDeposed{
|
||||||
@ -98,7 +108,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
|||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.Provider,
|
Provider: n.ProviderName,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
@ -114,7 +124,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
|||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalReadStateDeposed{
|
&EvalReadStateDeposed{
|
||||||
@ -147,7 +157,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
|||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.Provider,
|
Provider: n.ProviderName,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
@ -127,12 +127,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
|
|||||||
&AttachResourceConfigTransformer{Module: t.Module},
|
&AttachResourceConfigTransformer{Module: t.Module},
|
||||||
&AttachStateTransformer{State: t.State},
|
&AttachStateTransformer{State: t.State},
|
||||||
|
|
||||||
// Add providers since they can affect destroy order as well
|
TransformProviders(nil, providerFn, t.Module),
|
||||||
&MissingProviderTransformer{AllowAny: true, Concrete: providerFn},
|
|
||||||
&ProviderTransformer{},
|
|
||||||
&DisableProviderTransformer{},
|
|
||||||
&ParentProviderTransformer{},
|
|
||||||
&AttachProviderConfigTransformer{Module: t.Module},
|
|
||||||
|
|
||||||
// Add all the variables. We can depend on resources through
|
// Add all the variables. We can depend on resources through
|
||||||
// variables due to module parameters, and we need to properly
|
// variables due to module parameters, and we need to properly
|
||||||
|
@ -21,9 +21,9 @@ func (t *ImportStateTransformer) Transform(g *Graph) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodes = append(nodes, &graphNodeImportState{
|
nodes = append(nodes, &graphNodeImportState{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
ID: target.ID,
|
ID: target.ID,
|
||||||
Provider: target.Provider,
|
ProviderName: target.Provider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,9 +36,10 @@ func (t *ImportStateTransformer) Transform(g *Graph) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type graphNodeImportState struct {
|
type graphNodeImportState struct {
|
||||||
Addr *ResourceAddress // Addr is the resource address to import to
|
Addr *ResourceAddress // Addr is the resource address to import to
|
||||||
ID string // ID is the ID to import as
|
ID string // ID is the ID to import as
|
||||||
Provider string // Provider string
|
ProviderName string // Provider string
|
||||||
|
ResolvedProvider string // provider node address
|
||||||
|
|
||||||
states []*InstanceState
|
states []*InstanceState
|
||||||
}
|
}
|
||||||
@ -48,7 +49,11 @@ func (n *graphNodeImportState) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeImportState) ProvidedBy() []string {
|
func (n *graphNodeImportState) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.Addr.Type, n.Provider)}
|
return []string{resourceProvider(n.Addr.Type, n.ProviderName)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *graphNodeImportState) SetProvider(p string) {
|
||||||
|
n.ResolvedProvider = p
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeSubPath
|
// GraphNodeSubPath
|
||||||
@ -72,7 +77,7 @@ func (n *graphNodeImportState) EvalTree() EvalNode {
|
|||||||
return &EvalSequence{
|
return &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: n.ProvidedBy()[0],
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalImportState{
|
&EvalImportState{
|
||||||
@ -149,10 +154,11 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||||||
// is safe.
|
// is safe.
|
||||||
for i, state := range n.states {
|
for i, state := range n.states {
|
||||||
g.Add(&graphNodeImportStateSub{
|
g.Add(&graphNodeImportStateSub{
|
||||||
Target: addrs[i],
|
Target: addrs[i],
|
||||||
Path_: n.Path(),
|
Path_: n.Path(),
|
||||||
State: state,
|
State: state,
|
||||||
Provider: n.Provider,
|
ProviderName: n.ProviderName,
|
||||||
|
ResolvedProvider: n.ResolvedProvider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,10 +176,11 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||||||
// and is part of the subgraph. This node is responsible for refreshing
|
// and is part of the subgraph. This node is responsible for refreshing
|
||||||
// and adding a resource to the state once it is imported.
|
// and adding a resource to the state once it is imported.
|
||||||
type graphNodeImportStateSub struct {
|
type graphNodeImportStateSub struct {
|
||||||
Target *ResourceAddress
|
Target *ResourceAddress
|
||||||
State *InstanceState
|
State *InstanceState
|
||||||
Path_ []string
|
Path_ []string
|
||||||
Provider string
|
ProviderName string
|
||||||
|
ResolvedProvider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeImportStateSub) Name() string {
|
func (n *graphNodeImportStateSub) Name() string {
|
||||||
@ -216,7 +223,7 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode {
|
|||||||
return &EvalSequence{
|
return &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
&EvalGetProvider{
|
&EvalGetProvider{
|
||||||
Name: resourceProvider(info.Type, n.Provider),
|
Name: n.ResolvedProvider,
|
||||||
Output: &provider,
|
Output: &provider,
|
||||||
},
|
},
|
||||||
&EvalRefresh{
|
&EvalRefresh{
|
||||||
@ -233,7 +240,7 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode {
|
|||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: key.String(),
|
Name: key.String(),
|
||||||
ResourceType: info.Type,
|
ResourceType: info.Type,
|
||||||
Provider: resourceProvider(info.Type, n.Provider),
|
Provider: resourceProvider(info.Type, n.ProviderName),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -6,14 +6,49 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/hashicorp/terraform/config/module"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: return the transformers and append them to the list, so we don't lose the log steps
|
||||||
|
func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, mod *module.Tree) GraphTransformer {
|
||||||
|
// If we have no providers, let the MissingProviderTransformer add anything required.
|
||||||
|
// This is used by the destroy edge transformer's internal dependency graph.
|
||||||
|
allowAny := providers == nil
|
||||||
|
|
||||||
|
return GraphTransformMulti(
|
||||||
|
// Add providers from the config
|
||||||
|
&ProviderConfigTransformer{
|
||||||
|
Module: mod,
|
||||||
|
Providers: providers,
|
||||||
|
Concrete: concrete,
|
||||||
|
},
|
||||||
|
// Add any remaining missing providers
|
||||||
|
&MissingProviderTransformer{
|
||||||
|
AllowAny: allowAny,
|
||||||
|
Providers: providers,
|
||||||
|
Concrete: concrete,
|
||||||
|
},
|
||||||
|
// Connect the providers
|
||||||
|
&ProviderTransformer{},
|
||||||
|
// Disable unused providers
|
||||||
|
&DisableProviderTransformer{},
|
||||||
|
// Connect provider to their parent provider nodes
|
||||||
|
&ParentProviderTransformer{},
|
||||||
|
// Attach configuration to each provider instance
|
||||||
|
&AttachProviderConfigTransformer{
|
||||||
|
Module: mod,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeProvider is an interface that nodes that can be a provider
|
// GraphNodeProvider is an interface that nodes that can be a provider
|
||||||
// must implement. The ProviderName returned is the name of the provider
|
// must implement.
|
||||||
// they satisfy.
|
// ProviderName returns the name of the provider this satisfies.
|
||||||
|
// Name returns the full name of the provider in the config.
|
||||||
type GraphNodeProvider interface {
|
type GraphNodeProvider interface {
|
||||||
ProviderName() string
|
ProviderName() string
|
||||||
|
Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeCloseProvider is an interface that nodes that can be a close
|
// GraphNodeCloseProvider is an interface that nodes that can be a close
|
||||||
@ -27,7 +62,10 @@ type GraphNodeCloseProvider interface {
|
|||||||
// a provider must implement. ProvidedBy must return the name of the provider
|
// a provider must implement. ProvidedBy must return the name of the provider
|
||||||
// to use.
|
// to use.
|
||||||
type GraphNodeProviderConsumer interface {
|
type GraphNodeProviderConsumer interface {
|
||||||
|
// TODO: make this return s string instead of a []string
|
||||||
ProvidedBy() []string
|
ProvidedBy() []string
|
||||||
|
// Set the resolved provider address for this resource.
|
||||||
|
SetProvider(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProviderTransformer is a GraphTransformer that maps resources to
|
// ProviderTransformer is a GraphTransformer that maps resources to
|
||||||
@ -41,18 +79,43 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
|||||||
m := providerVertexMap(g)
|
m := providerVertexMap(g)
|
||||||
for _, v := range g.Vertices() {
|
for _, v := range g.Vertices() {
|
||||||
if pv, ok := v.(GraphNodeProviderConsumer); ok {
|
if pv, ok := v.(GraphNodeProviderConsumer); ok {
|
||||||
for _, p := range pv.ProvidedBy() {
|
p := pv.ProvidedBy()[0]
|
||||||
target := m[providerMapKey(p, pv)]
|
|
||||||
if target == nil {
|
key := providerMapKey(p, pv)
|
||||||
println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv)))
|
target := m[key]
|
||||||
err = multierror.Append(err, fmt.Errorf(
|
|
||||||
"%s: provider %s couldn't be found",
|
sp, ok := pv.(GraphNodeSubPath)
|
||||||
dag.VertexName(v), p))
|
if !ok && target == nil {
|
||||||
continue
|
// no target, and no path to walk up
|
||||||
|
err = multierror.Append(err, fmt.Errorf(
|
||||||
|
"%s: provider %s couldn't be found",
|
||||||
|
dag.VertexName(v), p))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we don't have a provider at this level, walk up the path looking for one
|
||||||
|
for i := 1; target == nil; i++ {
|
||||||
|
path := normalizeModulePath(sp.Path())
|
||||||
|
if len(path) < i {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Connect(dag.BasicEdge(v, target))
|
key = ResolveProviderName(p, path[:len(path)-i])
|
||||||
|
target = m[key]
|
||||||
|
if target != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if target == nil {
|
||||||
|
err = multierror.Append(err, fmt.Errorf(
|
||||||
|
"%s: provider %s couldn't be found",
|
||||||
|
dag.VertexName(v), p))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pv.SetProvider(key)
|
||||||
|
g.Connect(dag.BasicEdge(v, target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,38 +128,35 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
|||||||
// in the graph are evaluated.
|
// in the graph are evaluated.
|
||||||
type CloseProviderTransformer struct{}
|
type CloseProviderTransformer struct{}
|
||||||
|
|
||||||
|
// FIXME: this doesn't close providers if the root provider is disabled
|
||||||
func (t *CloseProviderTransformer) Transform(g *Graph) error {
|
func (t *CloseProviderTransformer) Transform(g *Graph) error {
|
||||||
pm := providerVertexMap(g)
|
pm := providerVertexMap(g)
|
||||||
cpm := closeProviderVertexMap(g)
|
cpm := make(map[string]*graphNodeCloseProvider)
|
||||||
var err error
|
var err error
|
||||||
for _, v := range g.Vertices() {
|
|
||||||
if pv, ok := v.(GraphNodeProviderConsumer); ok {
|
|
||||||
for _, p := range pv.ProvidedBy() {
|
|
||||||
key := p
|
|
||||||
source := cpm[key]
|
|
||||||
|
|
||||||
if source == nil {
|
for _, v := range pm {
|
||||||
// Create a new graphNodeCloseProvider and add it to the graph
|
p := v.(GraphNodeProvider)
|
||||||
source = &graphNodeCloseProvider{ProviderNameValue: p}
|
|
||||||
g.Add(source)
|
|
||||||
|
|
||||||
// Close node needs to depend on provider
|
// get the close provider of this type if we alread created it
|
||||||
provider, ok := pm[key]
|
closer := cpm[p.ProviderName()]
|
||||||
if !ok {
|
|
||||||
err = multierror.Append(err, fmt.Errorf(
|
|
||||||
"%s: provider %s couldn't be found for closing",
|
|
||||||
dag.VertexName(v), p))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
g.Connect(dag.BasicEdge(source, provider))
|
|
||||||
|
|
||||||
// Make sure we also add the new graphNodeCloseProvider to the map
|
if closer == nil {
|
||||||
// so we don't create and add any duplicate graphNodeCloseProviders.
|
// create a closer for this provider type
|
||||||
cpm[key] = source
|
closer = &graphNodeCloseProvider{ProviderNameValue: p.ProviderName()}
|
||||||
}
|
g.Add(closer)
|
||||||
|
cpm[p.ProviderName()] = closer
|
||||||
|
}
|
||||||
|
|
||||||
// Close node depends on all nodes provided by the provider
|
// Close node depends on the provider itself
|
||||||
g.Connect(dag.BasicEdge(source, v))
|
// this is added unconditionally, so it will connect to all instances
|
||||||
|
// of the provider. Extra edges will be removed by transitive
|
||||||
|
// reduction.
|
||||||
|
g.Connect(dag.BasicEdge(closer, p))
|
||||||
|
|
||||||
|
// connect all the provider's resources to the close node
|
||||||
|
for _, s := range g.UpEdges(p).List() {
|
||||||
|
if _, ok := s.(GraphNodeProviderConsumer); ok {
|
||||||
|
g.Connect(dag.BasicEdge(closer, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,10 +164,10 @@ func (t *CloseProviderTransformer) Transform(g *Graph) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MissingProviderTransformer is a GraphTransformer that adds nodes
|
// MissingProviderTransformer is a GraphTransformer that adds nodes for all
|
||||||
// for missing providers into the graph. Specifically, it creates provider
|
// required providers into the graph. Specifically, it creates provider
|
||||||
// configuration nodes for all the providers that we support. These are
|
// configuration nodes for all the providers that we support. These are pruned
|
||||||
// pruned later during an optimization pass.
|
// later during an optimization pass.
|
||||||
type MissingProviderTransformer struct {
|
type MissingProviderTransformer struct {
|
||||||
// Providers is the list of providers we support.
|
// Providers is the list of providers we support.
|
||||||
Providers []string
|
Providers []string
|
||||||
@ -134,93 +194,62 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
|
|||||||
supported[v] = struct{}{}
|
supported[v] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the map of providers we already have in our graph
|
var err error
|
||||||
m := providerVertexMap(g)
|
m := providerVertexMap(g)
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
// Go through all the provider consumers and make sure we add
|
|
||||||
// that provider if it is missing. We use a for loop here instead
|
|
||||||
// of "range" since we'll modify check as we go to add more to check.
|
|
||||||
check := g.Vertices()
|
|
||||||
for i := 0; i < len(check); i++ {
|
|
||||||
v := check[i]
|
|
||||||
|
|
||||||
pv, ok := v.(GraphNodeProviderConsumer)
|
pv, ok := v.(GraphNodeProviderConsumer)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this node has a subpath, then we use that as a prefix
|
p := pv.ProvidedBy()[0]
|
||||||
// into our map to check for an existing provider.
|
|
||||||
var path []string
|
var path []string
|
||||||
if sp, ok := pv.(GraphNodeSubPath); ok {
|
if sp, ok := pv.(GraphNodeSubPath); ok {
|
||||||
raw := normalizeModulePath(sp.Path())
|
path = sp.Path()
|
||||||
if len(raw) > len(rootModulePath) {
|
|
||||||
path = raw
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range pv.ProvidedBy() {
|
key := providerMapKey(p, pv)
|
||||||
key := providerMapKey(p, pv)
|
|
||||||
if _, ok := m[key]; ok {
|
provider := m[key]
|
||||||
// This provider already exists as a configure node
|
|
||||||
|
// if we don't have a provider at this level, walk up the path looking for one
|
||||||
|
for i := 1; provider == nil && len(path) >= i; i++ {
|
||||||
|
key = ResolveProviderName(p, normalizeModulePath(path[:len(path)-i]))
|
||||||
|
provider = m[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider != nil {
|
||||||
|
// we found a provider, but make sure there's a top-level provider too
|
||||||
|
if _, ok := m[ResolveProviderName(p, nil)]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 !t.AllowAny {
|
|
||||||
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 the missing provider node to the graph
|
|
||||||
v := t.Concrete(&NodeAbstractProvider{
|
|
||||||
NameValue: p,
|
|
||||||
PathValue: path,
|
|
||||||
}).(dag.Vertex)
|
|
||||||
if len(path) > 0 {
|
|
||||||
// We'll need the parent provider as well, so let's
|
|
||||||
// add a dummy node to check to make sure that we add
|
|
||||||
// that parent provider.
|
|
||||||
check = append(check, &graphNodeProviderConsumerDummy{
|
|
||||||
ProviderValue: p,
|
|
||||||
PathValue: path[:len(path)-1],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
m[key] = g.Add(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// always add a new top level provider
|
||||||
|
provider = t.Concrete(&NodeAbstractProvider{
|
||||||
|
NameValue: p,
|
||||||
|
}).(dag.Vertex)
|
||||||
|
|
||||||
|
key = ResolveProviderName(p, nil)
|
||||||
|
m[key] = g.Add(provider)
|
||||||
|
|
||||||
|
pv.SetProvider(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParentProviderTransformer connects provider nodes to their parents.
|
// ParentProviderTransformer connects provider nodes to their parents.
|
||||||
//
|
//
|
||||||
// This works by finding nodes that are both GraphNodeProviders and
|
// This works by finding nodes that are both GraphNodeProviders and
|
||||||
// GraphNodeSubPath. It then connects the providers to their parent
|
// GraphNodeSubPath. It then connects the providers to their parent
|
||||||
// path.
|
// path. The parent provider is always at the root level.
|
||||||
type ParentProviderTransformer struct{}
|
type ParentProviderTransformer struct{}
|
||||||
|
|
||||||
func (t *ParentProviderTransformer) Transform(g *Graph) error {
|
func (t *ParentProviderTransformer) Transform(g *Graph) error {
|
||||||
// Make a mapping of path to dag.Vertex, where path is: "path.name"
|
pm := providerVertexMap(g)
|
||||||
m := make(map[string]dag.Vertex)
|
for _, v := range g.Vertices() {
|
||||||
|
|
||||||
// Also create a map that maps a provider to its parent
|
|
||||||
parentMap := make(map[dag.Vertex]string)
|
|
||||||
for _, raw := range g.Vertices() {
|
|
||||||
// If it is the flat version, then make it the non-flat version.
|
|
||||||
// We eventually want to get rid of the flat version entirely so
|
|
||||||
// this is a stop-gap while it still exists.
|
|
||||||
var v dag.Vertex = raw
|
|
||||||
|
|
||||||
// Only care about providers
|
// Only care about providers
|
||||||
pn, ok := v.(GraphNodeProvider)
|
pn, ok := v.(GraphNodeProvider)
|
||||||
if !ok || pn.ProviderName() == "" {
|
if !ok || pn.ProviderName() == "" {
|
||||||
@ -228,34 +257,22 @@ func (t *ParentProviderTransformer) Transform(g *Graph) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also require a subpath, if there is no subpath then we
|
// Also require a subpath, if there is no subpath then we
|
||||||
// just totally ignore it. The expectation of this transform is
|
// can't have a parent.
|
||||||
// that it is used with a graph builder that is already flattened.
|
if pn, ok := v.(GraphNodeSubPath); ok {
|
||||||
var path []string
|
if len(normalizeModulePath(pn.Path())) <= 1 {
|
||||||
if pn, ok := raw.(GraphNodeSubPath); ok {
|
continue
|
||||||
path = pn.Path()
|
}
|
||||||
}
|
}
|
||||||
path = normalizeModulePath(path)
|
|
||||||
|
|
||||||
// Build the key with path.name i.e. "child.subchild.aws"
|
// this provider may be disabled, but we can only get it's name from
|
||||||
key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
|
// the ProviderName string
|
||||||
m[key] = raw
|
name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil)
|
||||||
|
parent := pm[name]
|
||||||
// Determine the parent if we're non-root. This is length 1 since
|
if parent != nil {
|
||||||
// the 0 index should be "root" since we normalize above.
|
|
||||||
if len(path) > 1 {
|
|
||||||
path = path[:len(path)-1]
|
|
||||||
key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
|
|
||||||
parentMap[raw] = key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect!
|
|
||||||
for v, key := range parentMap {
|
|
||||||
if parent, ok := m[key]; ok {
|
|
||||||
g.Connect(dag.BasicEdge(v, parent))
|
g.Connect(dag.BasicEdge(v, parent))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,23 +302,21 @@ func (t *PruneProviderTransformer) Transform(g *Graph) error {
|
|||||||
// providerMapKey is a helper that gives us the key to use for the
|
// providerMapKey is a helper that gives us the key to use for the
|
||||||
// maps returned by things such as providerVertexMap.
|
// maps returned by things such as providerVertexMap.
|
||||||
func providerMapKey(k string, v dag.Vertex) string {
|
func providerMapKey(k string, v dag.Vertex) string {
|
||||||
pathPrefix := ""
|
// we create a dummy provider to
|
||||||
|
var path []string
|
||||||
if sp, ok := v.(GraphNodeSubPath); ok {
|
if sp, ok := v.(GraphNodeSubPath); ok {
|
||||||
raw := normalizeModulePath(sp.Path())
|
path = normalizeModulePath(sp.Path())
|
||||||
if len(raw) > len(rootModulePath) {
|
|
||||||
pathPrefix = modulePrefixStr(raw) + "."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return ResolveProviderName(k, path)
|
||||||
return pathPrefix + k
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func providerVertexMap(g *Graph) map[string]dag.Vertex {
|
func providerVertexMap(g *Graph) map[string]dag.Vertex {
|
||||||
m := make(map[string]dag.Vertex)
|
m := make(map[string]dag.Vertex)
|
||||||
for _, v := range g.Vertices() {
|
for _, v := range g.Vertices() {
|
||||||
if pv, ok := v.(GraphNodeProvider); ok {
|
if pv, ok := v.(GraphNodeProvider); ok {
|
||||||
key := providerMapKey(pv.ProviderName(), v)
|
// TODO: The Name may have meta info, like " (disabled)"
|
||||||
m[key] = v
|
name := strings.SplitN(pv.Name(), " ", 2)[0]
|
||||||
|
m[name] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,3 +393,5 @@ func (n *graphNodeProviderConsumerDummy) Path() []string {
|
|||||||
func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
|
func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
|
||||||
return []string{n.ProviderValue}
|
return []string{n.ProviderValue}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *graphNodeProviderConsumerDummy) SetProvider(string) {}
|
||||||
|
@ -3,6 +3,8 @@ package terraform
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProviderTransformer(t *testing.T) {
|
func TestProviderTransformer(t *testing.T) {
|
||||||
@ -178,6 +180,13 @@ func TestMissingProviderTransformer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transform := &ProviderTransformer{}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
transform := &CloseProviderTransformer{}
|
transform := &CloseProviderTransformer{}
|
||||||
if err := transform.Transform(&g); err != nil {
|
if err := transform.Transform(&g); err != nil {
|
||||||
@ -188,7 +197,47 @@ func TestMissingProviderTransformer(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testTransformMissingProviderBasicStr)
|
expected := strings.TrimSpace(testTransformMissingProviderBasicStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMissingProviderTransformer_grandchildMissing(t *testing.T) {
|
||||||
|
mod := testModule(t, "transform-provider-missing-grandchild")
|
||||||
|
|
||||||
|
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
|
||||||
|
|
||||||
|
g := Graph{Path: RootModulePath}
|
||||||
|
{
|
||||||
|
tf := &ConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transform := &AttachResourceConfigTransformer{Module: mod}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transform := TransformProviders([]string{"aws", "foo", "bar"}, concrete, mod)
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
transform := &TransitiveReductionTransformer{}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testTransformMissingGrandchildProviderStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +305,7 @@ func TestMissingProviderTransformer_moduleGrandchild(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testTransformMissingProviderModuleGrandchildStr)
|
expected := strings.TrimSpace(testTransformMissingProviderModuleGrandchildStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +346,7 @@ func TestParentProviderTransformer(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testTransformParentProviderStr)
|
expected := strings.TrimSpace(testTransformParentProviderStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +388,7 @@ func TestParentProviderTransformer_moduleGrandchild(t *testing.T) {
|
|||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testTransformParentProviderModuleGrandchildStr)
|
expected := strings.TrimSpace(testTransformParentProviderModuleGrandchildStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +462,9 @@ provider.aws (close)
|
|||||||
|
|
||||||
const testTransformMissingProviderBasicStr = `
|
const testTransformMissingProviderBasicStr = `
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
|
provider.aws
|
||||||
foo_instance.web
|
foo_instance.web
|
||||||
|
provider.foo
|
||||||
provider.aws
|
provider.aws
|
||||||
provider.aws (close)
|
provider.aws (close)
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
@ -424,39 +475,40 @@ provider.foo (close)
|
|||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testTransformMissingGrandchildProviderStr = `
|
||||||
|
module.sub.module.subsub.bar_instance.two
|
||||||
|
provider.bar
|
||||||
|
module.sub.module.subsub.foo_instance.one
|
||||||
|
module.sub.provider.foo
|
||||||
|
module.sub.provider.foo
|
||||||
|
provider.foo (disabled)
|
||||||
|
provider.bar
|
||||||
|
provider.foo (disabled)
|
||||||
|
`
|
||||||
|
|
||||||
const testTransformMissingProviderModuleChildStr = `
|
const testTransformMissingProviderModuleChildStr = `
|
||||||
module.moo.foo_instance.qux (import id: bar)
|
module.moo.foo_instance.qux (import id: bar)
|
||||||
module.moo.provider.foo
|
|
||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTransformMissingProviderModuleGrandchildStr = `
|
const testTransformMissingProviderModuleGrandchildStr = `
|
||||||
module.a.module.b.foo_instance.qux (import id: bar)
|
module.a.module.b.foo_instance.qux (import id: bar)
|
||||||
module.a.module.b.provider.foo
|
|
||||||
module.a.provider.foo
|
|
||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTransformParentProviderStr = `
|
const testTransformParentProviderStr = `
|
||||||
module.moo.foo_instance.qux (import id: bar)
|
module.moo.foo_instance.qux (import id: bar)
|
||||||
module.moo.provider.foo
|
|
||||||
provider.foo
|
|
||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTransformParentProviderModuleGrandchildStr = `
|
const testTransformParentProviderModuleGrandchildStr = `
|
||||||
module.a.module.b.foo_instance.qux (import id: bar)
|
module.a.module.b.foo_instance.qux (import id: bar)
|
||||||
module.a.module.b.provider.foo
|
|
||||||
module.a.provider.foo
|
|
||||||
module.a.provider.foo
|
|
||||||
provider.foo
|
|
||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTransformProviderModuleChildStr = `
|
const testTransformProviderModuleChildStr = `
|
||||||
module.moo.foo_instance.qux (import id: bar)
|
module.moo.foo_instance.qux (import id: bar)
|
||||||
module.moo.provider.foo
|
provider.foo
|
||||||
module.moo.provider.foo
|
|
||||||
provider.foo
|
provider.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -335,8 +335,13 @@ func ReferenceFromInterpolatedVar(v config.InterpolatedVariable) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func modulePrefixStr(p []string) string {
|
func modulePrefixStr(p []string) string {
|
||||||
|
// strip "root"
|
||||||
|
if len(p) > 0 && p[0] == rootModulePath[0] {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
|
||||||
parts := make([]string, 0, len(p)*2)
|
parts := make([]string, 0, len(p)*2)
|
||||||
for _, p := range p[1:] {
|
for _, p := range p {
|
||||||
parts = append(parts, "module", p)
|
parts = append(parts, "module", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,9 @@ func (t *ResourceCountTransformer) Transform(g *Graph) error {
|
|||||||
addr.Index = index
|
addr.Index = index
|
||||||
|
|
||||||
// Build the abstract node and the concrete one
|
// Build the abstract node and the concrete one
|
||||||
abstract := &NodeAbstractResource{Addr: addr}
|
abstract := &NodeAbstractResource{
|
||||||
|
Addr: addr,
|
||||||
|
}
|
||||||
var node dag.Vertex = abstract
|
var node dag.Vertex = abstract
|
||||||
if f := t.Concrete; f != nil {
|
if f := t.Concrete; f != nil {
|
||||||
node = f(abstract)
|
node = f(abstract)
|
||||||
|
Loading…
Reference in New Issue
Block a user