Merge pull request #16586 from hashicorp/jbardin/providers
Store resolved providers in state
This commit is contained in:
commit
00b7715710
|
@ -53,6 +53,7 @@ func TestLocal_applyBasic(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +161,7 @@ func TestLocal_applyError(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +213,7 @@ func TestLocal_applyBackendFail(t *testing.T) {
|
||||||
checkState(t, "errored.tfstate", `
|
checkState(t, "errored.tfstate", `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,48 +199,6 @@ func TestLocal_planDestroy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocal_planDestroyNoConfig(t *testing.T) {
|
|
||||||
b := TestLocal(t)
|
|
||||||
p := TestLocalProvider(t, b, "test")
|
|
||||||
terraform.TestStateFile(t, b.StatePath, testPlanState())
|
|
||||||
|
|
||||||
outDir := testTempDir(t)
|
|
||||||
defer os.RemoveAll(outDir)
|
|
||||||
planPath := filepath.Join(outDir, "plan.tfplan")
|
|
||||||
|
|
||||||
op := testOperationPlan()
|
|
||||||
op.Destroy = true
|
|
||||||
op.PlanRefresh = true
|
|
||||||
op.Module = nil
|
|
||||||
op.PlanOutPath = planPath
|
|
||||||
|
|
||||||
run, err := b.Operation(context.Background(), op)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
<-run.Done()
|
|
||||||
if run.Err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !p.RefreshCalled {
|
|
||||||
t.Fatal("refresh should be called")
|
|
||||||
}
|
|
||||||
|
|
||||||
if run.PlanEmpty {
|
|
||||||
t.Fatal("plan should not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
plan := testReadPlan(t, planPath)
|
|
||||||
for _, m := range plan.Diff.Modules {
|
|
||||||
for _, r := range m.Resources {
|
|
||||||
if !r.Destroy {
|
|
||||||
t.Fatalf("bad: %#v", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLocal_planOutPathNoChange(t *testing.T) {
|
func TestLocal_planOutPathNoChange(t *testing.T) {
|
||||||
b := TestLocal(t)
|
b := TestLocal(t)
|
||||||
TestLocalProvider(t, b, "test")
|
TestLocalProvider(t, b, "test")
|
||||||
|
|
|
@ -37,6 +37,7 @@ func TestLocal_refresh(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ func TestLocal_refreshNilModule(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +96,7 @@ func TestLocal_refreshNilModuleWithInput(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +140,7 @@ func TestLocal_refreshInput(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +174,7 @@ func TestLocal_refreshValidate(t *testing.T) {
|
||||||
checkState(t, b.StateOutPath, `
|
checkState(t, b.StateOutPath, `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ func TestLocal_backend(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkState(t *testing.T, path, expected string) {
|
func checkState(t *testing.T, path, expected string) {
|
||||||
|
t.Helper()
|
||||||
// Read the state
|
// Read the state
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -663,11 +663,11 @@ func TestImport_pluginDir(t *testing.T) {
|
||||||
const testImportStr = `
|
const testImportStr = `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yay
|
ID = yay
|
||||||
provider = test
|
provider = provider.test
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportCustomProviderStr = `
|
const testImportCustomProviderStr = `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yay
|
ID = yay
|
||||||
provider = test.alias
|
provider = provider.test.alias
|
||||||
`
|
`
|
||||||
|
|
|
@ -802,8 +802,10 @@ foo = "bar"
|
||||||
const testRefreshStr = `
|
const testRefreshStr = `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`
|
`
|
||||||
const testRefreshCwdStr = `
|
const testRefreshCwdStr = `
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = yes
|
ID = yes
|
||||||
|
provider = provider.test
|
||||||
`
|
`
|
||||||
|
|
|
@ -69,15 +69,6 @@ type ProviderConfig struct {
|
||||||
Alias string
|
Alias string
|
||||||
Version string
|
Version string
|
||||||
RawConfig *RawConfig
|
RawConfig *RawConfig
|
||||||
|
|
||||||
// Path records where the Provider was declared in a module tree, so that
|
|
||||||
// it can be copied into child module providers yet still interpolated in
|
|
||||||
// the correct scope.
|
|
||||||
Path []string
|
|
||||||
|
|
||||||
// Inherited is used to skip validation of this config, since any
|
|
||||||
// interpolated variables won't be declared at this level.
|
|
||||||
Inherited bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A resource represents a single Terraform resource in the configuration.
|
// A resource represents a single Terraform resource in the configuration.
|
||||||
|
@ -270,7 +261,9 @@ func (r *Resource) ProviderFullName() string {
|
||||||
// the provider name is inferred from the resource type name.
|
// the provider name is inferred from the resource type name.
|
||||||
func ResourceProviderFullName(resourceType, explicitProvider string) string {
|
func ResourceProviderFullName(resourceType, explicitProvider string) string {
|
||||||
if explicitProvider != "" {
|
if explicitProvider != "" {
|
||||||
return explicitProvider
|
// check for an explicit provider name, or return the original
|
||||||
|
parts := strings.SplitAfter(explicitProvider, "provider.")
|
||||||
|
return parts[len(parts)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := strings.IndexRune(resourceType, '_')
|
idx := strings.IndexRune(resourceType, '_')
|
||||||
|
@ -817,10 +810,6 @@ func (c *Config) rawConfigs() map[string]*RawConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pc := range c.ProviderConfigs {
|
for _, pc := range c.ProviderConfigs {
|
||||||
// this was an inherited config, so we don't validate it at this level.
|
|
||||||
if pc.Inherited {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
source := fmt.Sprintf("provider config '%s'", pc.Name)
|
source := fmt.Sprintf("provider config '%s'", pc.Name)
|
||||||
result[source] = pc.RawConfig
|
result[source] = pc.RawConfig
|
||||||
}
|
}
|
||||||
|
|
|
@ -851,7 +851,6 @@ func TestLoadFile_ignoreChanges(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := resourcesStr(c.Resources)
|
actual := resourcesStr(c.Resources)
|
||||||
print(actual)
|
|
||||||
if actual != strings.TrimSpace(ignoreChangesResourcesStr) {
|
if actual != strings.TrimSpace(ignoreChangesResourcesStr) {
|
||||||
t.Fatalf("bad:\n%s", actual)
|
t.Fatalf("bad:\n%s", actual)
|
||||||
}
|
}
|
||||||
|
@ -943,7 +942,6 @@ func TestLoad_hclAttributes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := resourcesStr(c.Resources)
|
actual := resourcesStr(c.Resources)
|
||||||
print(actual)
|
|
||||||
if actual != strings.TrimSpace(jsonAttributeStr) {
|
if actual != strings.TrimSpace(jsonAttributeStr) {
|
||||||
t.Fatalf("bad:\n%s", actual)
|
t.Fatalf("bad:\n%s", actual)
|
||||||
}
|
}
|
||||||
|
@ -988,7 +986,6 @@ func TestLoad_jsonAttributes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := resourcesStr(c.Resources)
|
actual := resourcesStr(c.Resources)
|
||||||
print(actual)
|
|
||||||
if actual != strings.TrimSpace(jsonAttributeStr) {
|
if actual != strings.TrimSpace(jsonAttributeStr) {
|
||||||
t.Fatalf("bad:\n%s", actual)
|
t.Fatalf("bad:\n%s", actual)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
provider "top" {}
|
|
||||||
|
|
||||||
provider "bottom" {
|
|
||||||
alias = "foo"
|
|
||||||
value = "from bottom"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "c" {
|
|
||||||
source = "../c"
|
|
||||||
providers = {
|
|
||||||
"bottom" = "bottom.foo"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
# Hello
|
|
||||||
provider "bottom" {}
|
|
|
@ -1,11 +0,0 @@
|
||||||
provider "top" {
|
|
||||||
alias = "foo"
|
|
||||||
value = "from top"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "a" {
|
|
||||||
source = "./a"
|
|
||||||
providers = {
|
|
||||||
"top" = "top.foo"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -188,11 +188,6 @@ func (t *Tree) Load(s *Storage) error {
|
||||||
// Set our tree up
|
// Set our tree up
|
||||||
t.children = children
|
t.children = children
|
||||||
|
|
||||||
// if we're the root module, we can now set the provider inheritance
|
|
||||||
if len(t.path) == 0 {
|
|
||||||
t.inheritProviderConfigs(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,93 +343,6 @@ func (t *Tree) getChildren(s *Storage) (map[string]*Tree, error) {
|
||||||
return children, nil
|
return children, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// inheritProviderConfig resolves all provider config inheritance after the
|
|
||||||
// tree is loaded.
|
|
||||||
//
|
|
||||||
// If there is a provider block without a config, look in the parent's Module
|
|
||||||
// block for a provider, and fetch that provider's configuration. If that
|
|
||||||
// doesn't exist, assume a default empty config. Implicit providers can still
|
|
||||||
// inherit their config all the way up from the root, so walk up the tree and
|
|
||||||
// copy the first matching provider into the module.
|
|
||||||
func (t *Tree) inheritProviderConfigs(stack []*Tree) {
|
|
||||||
// the recursive calls only append, so we don't need to worry about copying
|
|
||||||
// this slice.
|
|
||||||
stack = append(stack, t)
|
|
||||||
for _, c := range t.children {
|
|
||||||
c.inheritProviderConfigs(stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stack) == 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
providers := make(map[string]*config.ProviderConfig)
|
|
||||||
missingProviders := make(map[string]bool)
|
|
||||||
|
|
||||||
for _, p := range t.config.ProviderConfigs {
|
|
||||||
providers[p.FullName()] = p
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range t.config.Resources {
|
|
||||||
p := r.ProviderFullName()
|
|
||||||
if _, ok := providers[p]; !(ok || strings.Contains(p, ".")) {
|
|
||||||
missingProviders[p] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get our parent's module config block
|
|
||||||
parent := stack[len(stack)-2]
|
|
||||||
var parentModule *config.Module
|
|
||||||
for _, m := range parent.config.Modules {
|
|
||||||
if m.Name == t.name {
|
|
||||||
parentModule = m
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if parentModule == nil {
|
|
||||||
panic("can't be a module without a parent module config")
|
|
||||||
}
|
|
||||||
|
|
||||||
// now look for providers that need a config
|
|
||||||
for p, pc := range providers {
|
|
||||||
if len(pc.RawConfig.RawMap()) > 0 {
|
|
||||||
log.Printf("[TRACE] provider %q has a config, continuing", p)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// this provider has no config yet, check for one being passed in
|
|
||||||
parentProviderName, ok := parentModule.Providers[p]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var parentProvider *config.ProviderConfig
|
|
||||||
// there's a config for us in the parent module
|
|
||||||
for _, pp := range parent.config.ProviderConfigs {
|
|
||||||
if pp.FullName() == parentProviderName {
|
|
||||||
parentProvider = pp
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if parentProvider == nil {
|
|
||||||
// no config found, assume defaults
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy it in, but set an interpolation Scope.
|
|
||||||
// An interpolation Scope always need to have "root"
|
|
||||||
pc.Path = append([]string{RootName}, parent.path...)
|
|
||||||
pc.RawConfig = parentProvider.RawConfig
|
|
||||||
log.Printf("[TRACE] provider %q inheriting config from %q",
|
|
||||||
strings.Join(append(t.Path(), pc.FullName()), "."),
|
|
||||||
strings.Join(append(parent.Path(), parentProvider.FullName()), "."),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path is the full path to this tree.
|
// Path is the full path to this tree.
|
||||||
func (t *Tree) Path() []string {
|
func (t *Tree) Path() []string {
|
||||||
return t.path
|
return t.path
|
||||||
|
|
|
@ -3,7 +3,6 @@ package module
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -548,69 +547,6 @@ func TestTreeValidate_unknownModule(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTreeProviders_basic(t *testing.T) {
|
|
||||||
storage := testStorage(t, nil)
|
|
||||||
tree := NewTree("", testConfig(t, "basic-parent-providers"))
|
|
||||||
|
|
||||||
storage.Mode = GetModeGet
|
|
||||||
if err := tree.Load(storage); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var a, b *Tree
|
|
||||||
for _, child := range tree.Children() {
|
|
||||||
if child.Name() == "a" {
|
|
||||||
a = child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProviders := tree.config.ProviderConfigsByFullName()
|
|
||||||
topRaw := rootProviders["top.foo"]
|
|
||||||
|
|
||||||
if a == nil {
|
|
||||||
t.Fatal("could not find module 'a'")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, child := range a.Children() {
|
|
||||||
if child.Name() == "c" {
|
|
||||||
b = child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if b == nil {
|
|
||||||
t.Fatal("could not find module 'c'")
|
|
||||||
}
|
|
||||||
|
|
||||||
aProviders := a.config.ProviderConfigsByFullName()
|
|
||||||
bottomRaw := aProviders["bottom.foo"]
|
|
||||||
bProviders := b.config.ProviderConfigsByFullName()
|
|
||||||
bBottom := bProviders["bottom"]
|
|
||||||
|
|
||||||
// compare the configs
|
|
||||||
// top.foo should have been copied to a.top
|
|
||||||
aTop := aProviders["top"]
|
|
||||||
if !reflect.DeepEqual(aTop.RawConfig.RawMap(), topRaw.RawConfig.RawMap()) {
|
|
||||||
log.Fatalf("expected config %#v, got %#v",
|
|
||||||
topRaw.RawConfig.RawMap(),
|
|
||||||
aTop.RawConfig.RawMap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(aTop.Path, []string{RootName}) {
|
|
||||||
log.Fatalf(`expected scope for "top": {"root"}, got %#v`, aTop.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(bBottom.RawConfig.RawMap(), bottomRaw.RawConfig.RawMap()) {
|
|
||||||
t.Fatalf("expected config %#v, got %#v",
|
|
||||||
bottomRaw.RawConfig.RawMap(),
|
|
||||||
bBottom.RawConfig.RawMap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(bBottom.Path, []string{RootName, "a"}) {
|
|
||||||
t.Fatalf(`expected scope for "bottom": {"root", "a"}, got %#v`, bBottom.Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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"))
|
||||||
|
|
|
@ -129,6 +129,7 @@ func TestContext2Apply_escape(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = "bar"
|
foo = "bar"
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -160,6 +161,7 @@ func TestContext2Apply_resourceCountOneList(t *testing.T) {
|
||||||
actual := strings.TrimSpace(state.String())
|
actual := strings.TrimSpace(state.String())
|
||||||
expected := strings.TrimSpace(`null_resource.foo:
|
expected := strings.TrimSpace(`null_resource.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.null
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
||||||
|
@ -578,6 +580,7 @@ amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-1234
|
||||||
module.test:
|
module.test:
|
||||||
null_resource.noop:
|
null_resource.noop:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.null
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
||||||
|
@ -745,6 +748,7 @@ func TestContext2Apply_providerWarning(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
|
t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
|
||||||
|
@ -1032,11 +1036,13 @@ func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
require_new = yes
|
require_new = yes
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
value = foo
|
value = foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
require_new = yes
|
require_new = yes
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -1170,10 +1176,12 @@ func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.bar.0:
|
aws_instance.bar.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.1:
|
aws_instance.bar.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -1233,6 +1241,7 @@ func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2007,6 +2016,7 @@ func TestContext2Apply_cancelBlock(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,6 +2076,7 @@ func TestContext2Apply_cancelProvisioner(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo: (tainted)
|
aws_instance.foo: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -2448,10 +2459,12 @@ func TestContext2Apply_mapVariableOverride(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
ami = overridden
|
ami = overridden
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
ami = image-1234
|
ami = image-1234
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -2619,7 +2632,7 @@ func TestContext2Apply_moduleInheritAlias(t *testing.T) {
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws.eu
|
provider = provider.aws.eu
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3140,6 +3153,7 @@ func TestContext2Apply_moduleTarget(t *testing.T) {
|
||||||
module.A:
|
module.A:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -3149,6 +3163,7 @@ module.A:
|
||||||
module.B:
|
module.B:
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -3929,6 +3944,7 @@ func TestContext2Apply_outputDependsOn(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
||||||
|
@ -4560,6 +4576,7 @@ func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.web: (1 deposed)
|
aws_instance.web: (1 deposed)
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
Deposed ID 1 = foo
|
Deposed ID 1 = foo
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
@ -4584,6 +4601,7 @@ aws_instance.web: (1 deposed)
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.web: (2 deposed)
|
aws_instance.web: (2 deposed)
|
||||||
ID = baz
|
ID = baz
|
||||||
|
provider = provider.aws
|
||||||
Deposed ID 1 = foo
|
Deposed ID 1 = foo
|
||||||
Deposed ID 2 = bar
|
Deposed ID 2 = bar
|
||||||
`)
|
`)
|
||||||
|
@ -4611,6 +4629,7 @@ aws_instance.web: (2 deposed)
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.web: (1 deposed)
|
aws_instance.web: (1 deposed)
|
||||||
ID = qux
|
ID = qux
|
||||||
|
provider = provider.aws
|
||||||
Deposed ID 1 = bar
|
Deposed ID 1 = bar
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
@ -4632,6 +4651,7 @@ aws_instance.web: (1 deposed)
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.web:
|
aws_instance.web:
|
||||||
ID = quux
|
ID = quux
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4672,6 +4692,7 @@ func TestContext2Apply_provisionerFailContinue(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -5067,6 +5088,7 @@ func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -5935,12 +5957,13 @@ func TestContext2Apply_destroyOrder(t *testing.T) {
|
||||||
|
|
||||||
t.Logf("State 1: %s", state)
|
t.Logf("State 1: %s", state)
|
||||||
|
|
||||||
// Next, plan and apply config-less to force a destroy with "apply"
|
// Next, plan and apply a destroy
|
||||||
h.Active = true
|
h.Active = true
|
||||||
ctx = testContext2(t, &ContextOpts{
|
ctx = testContext2(t, &ContextOpts{
|
||||||
State: state,
|
Destroy: true,
|
||||||
Module: module.NewEmptyTree(),
|
State: state,
|
||||||
Hooks: []Hook{h},
|
Module: m,
|
||||||
|
Hooks: []Hook{h},
|
||||||
ProviderResolver: ResourceProviderResolverFixed(
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
map[string]ResourceProviderFactory{
|
map[string]ResourceProviderFactory{
|
||||||
"aws": testProviderFuncFixed(p),
|
"aws": testProviderFuncFixed(p),
|
||||||
|
@ -7370,6 +7393,7 @@ func TestContext2Apply_targeted(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -7402,10 +7426,13 @@ func TestContext2Apply_targetedCount(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.2:
|
aws_instance.foo.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7436,6 +7463,7 @@ func TestContext2Apply_targetedCountIndex(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7673,10 +7701,12 @@ func TestContext2Apply_targetedModule(t *testing.T) {
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -7712,6 +7742,7 @@ func TestContext2Apply_targetedModuleDep(t *testing.T) {
|
||||||
checkStateString(t, state, `
|
checkStateString(t, state, `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -7721,6 +7752,7 @@ aws_instance.foo:
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.mod:
|
aws_instance.mod:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
||||||
|
@ -7795,6 +7827,7 @@ module.child1:
|
||||||
module.child2:
|
module.child2:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
||||||
|
@ -7836,6 +7869,7 @@ func TestContext2Apply_targetedModuleResource(t *testing.T) {
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -8289,6 +8323,7 @@ func TestContext2Apply_issue5254(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
template_file.child:
|
template_file.child:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.template
|
||||||
template = Hi
|
template = Hi
|
||||||
type = template_file
|
type = template_file
|
||||||
|
|
||||||
|
@ -8296,6 +8331,7 @@ template_file.child:
|
||||||
template_file.parent.*
|
template_file.parent.*
|
||||||
template_file.parent:
|
template_file.parent:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.template
|
||||||
template = Hi
|
template = Hi
|
||||||
type = template_file
|
type = template_file
|
||||||
`)
|
`)
|
||||||
|
@ -8371,6 +8407,7 @@ func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
aws_instance.iambeingadded:
|
aws_instance.iambeingadded:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.ifailedprovisioners: (tainted)
|
aws_instance.ifailedprovisioners: (tainted)
|
||||||
ID = ifailedprovisioners
|
ID = ifailedprovisioners
|
||||||
`)
|
`)
|
||||||
|
@ -8416,6 +8453,7 @@ func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
required_field = set
|
required_field = set
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -8560,6 +8598,7 @@ func TestContext2Apply_ignoreChangesWildcard(t *testing.T) {
|
||||||
expected := strings.TrimSpace(`
|
expected := strings.TrimSpace(`
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
required_field = set
|
required_field = set
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -8820,6 +8859,7 @@ func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
|
||||||
module.child.subchild:
|
module.child.subchild:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
@ -8868,7 +8908,6 @@ func TestContext2Apply_destroyWithLocals(t *testing.T) {
|
||||||
p.ApplyFn = testApplyFn
|
p.ApplyFn = testApplyFn
|
||||||
p.DiffFn = func(info *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
|
p.DiffFn = func(info *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
|
||||||
d, err := testDiffFn(info, s, c)
|
d, err := testDiffFn(info, s, c)
|
||||||
fmt.Println("DIFF:", d)
|
|
||||||
return d, err
|
return d, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8977,10 +9016,79 @@ func TestContext2Apply_providerWithLocals(t *testing.T) {
|
||||||
t.Fatal("expected no state, got:", state)
|
t.Fatal("expected no state, got:", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy won't work because the local value is removed before the
|
|
||||||
// provider. Once this is fixed this test will start to fail, and we
|
|
||||||
// can remove the invalid interpolation string;
|
|
||||||
if providerRegion != "bar" {
|
if providerRegion != "bar" {
|
||||||
t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
|
t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Apply_destroyWithProviders(t *testing.T) {
|
||||||
|
m := testModule(t, "destroy-module-with-provider")
|
||||||
|
p := testProvider("aws")
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
|
||||||
|
s := &State{
|
||||||
|
Modules: []*ModuleState{
|
||||||
|
&ModuleState{
|
||||||
|
Path: rootModulePath,
|
||||||
|
},
|
||||||
|
&ModuleState{
|
||||||
|
Path: []string{"root", "child"},
|
||||||
|
},
|
||||||
|
&ModuleState{
|
||||||
|
Path: []string{"root", "mod", "removed"},
|
||||||
|
Resources: map[string]*ResourceState{
|
||||||
|
"aws_instance.child": &ResourceState{
|
||||||
|
Type: "aws_instance",
|
||||||
|
Primary: &InstanceState{
|
||||||
|
ID: "bar",
|
||||||
|
},
|
||||||
|
// this provider doesn't exist
|
||||||
|
Provider: "provider.aws.baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: m,
|
||||||
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
|
map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
State: s,
|
||||||
|
Destroy: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// test that we can't destroy if the provider is missing
|
||||||
|
if _, err := ctx.Plan(); err == nil {
|
||||||
|
t.Fatal("expected plan error, provider.aws.baz doesn't exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// correct the state
|
||||||
|
s.Modules[2].Resources["aws_instance.child"].Provider = "provider.aws.bar"
|
||||||
|
|
||||||
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
state, err := ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error during apply: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := strings.TrimSpace(state.String())
|
||||||
|
|
||||||
|
// This should fail once modules are removed from the state entirely.
|
||||||
|
want := strings.TrimSpace(`
|
||||||
|
<no state>
|
||||||
|
module.child:
|
||||||
|
<no state>
|
||||||
|
module.mod.removed:
|
||||||
|
<no state>`)
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -801,13 +801,13 @@ func TestContextImport_customProvider(t *testing.T) {
|
||||||
const testImportStr = `
|
const testImportStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportCountIndexStr = `
|
const testImportCountIndexStr = `
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportCollisionStr = `
|
const testImportCollisionStr = `
|
||||||
|
@ -820,7 +820,7 @@ const testImportModuleStr = `
|
||||||
module.foo:
|
module.foo:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportModuleDepth2Str = `
|
const testImportModuleDepth2Str = `
|
||||||
|
@ -828,7 +828,7 @@ const testImportModuleDepth2Str = `
|
||||||
module.a.b:
|
module.a.b:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportModuleDiffStr = `
|
const testImportModuleDiffStr = `
|
||||||
|
@ -838,7 +838,7 @@ module.bar:
|
||||||
module.foo:
|
module.foo:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportModuleExistingStr = `
|
const testImportModuleExistingStr = `
|
||||||
|
@ -847,39 +847,39 @@ module.foo:
|
||||||
ID = bar
|
ID = bar
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportMultiStr = `
|
const testImportMultiStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
aws_instance_thing.foo:
|
aws_instance_thing.foo:
|
||||||
ID = bar
|
ID = bar
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportMultiSameStr = `
|
const testImportMultiSameStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
aws_instance_thing.foo:
|
aws_instance_thing.foo:
|
||||||
ID = bar
|
ID = bar
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
aws_instance_thing.foo-1:
|
aws_instance_thing.foo-1:
|
||||||
ID = qux
|
ID = qux
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportRefreshStr = `
|
const testImportRefreshStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
`
|
`
|
||||||
|
|
||||||
const testImportCustomProviderStr = `
|
const testImportCustomProviderStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws.alias
|
provider = provider.aws.alias
|
||||||
`
|
`
|
||||||
|
|
|
@ -564,6 +564,7 @@ func TestContext2Input_varWithDefault(t *testing.T) {
|
||||||
expectedStr := strings.TrimSpace(`
|
expectedStr := strings.TrimSpace(`
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = 123
|
foo = 123
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`)
|
`)
|
||||||
|
|
|
@ -3527,28 +3527,34 @@ STATE:
|
||||||
|
|
||||||
aws_instance.bar.0:
|
aws_instance.bar.0:
|
||||||
ID = bar0
|
ID = bar0
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo.*
|
aws_instance.foo.*
|
||||||
aws_instance.bar.1:
|
aws_instance.bar.1:
|
||||||
ID = bar1
|
ID = bar1
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo.*
|
aws_instance.foo.*
|
||||||
aws_instance.baz.0:
|
aws_instance.baz.0:
|
||||||
ID = baz0
|
ID = baz0
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.bar.*
|
aws_instance.bar.*
|
||||||
aws_instance.baz.1:
|
aws_instance.baz.1:
|
||||||
ID = baz1
|
ID = baz1
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.bar.*
|
aws_instance.bar.*
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo0
|
ID = foo0
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo1
|
ID = foo1
|
||||||
|
provider = provider.aws
|
||||||
`)
|
`)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
|
t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
|
||||||
|
|
|
@ -1110,3 +1110,53 @@ func TestContext2Refresh_noDiffHookOnScaleOut(t *testing.T) {
|
||||||
t.Fatal("PostDiff should not have been called")
|
t.Fatal("PostDiff should not have been called")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Refresh_updateProviderInState(t *testing.T) {
|
||||||
|
m := testModule(t, "update-resource-provider")
|
||||||
|
p := testProvider("aws")
|
||||||
|
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
|
||||||
|
s := &State{
|
||||||
|
Modules: []*ModuleState{
|
||||||
|
&ModuleState{
|
||||||
|
Path: rootModulePath,
|
||||||
|
Resources: map[string]*ResourceState{
|
||||||
|
"aws_instance.bar": &ResourceState{
|
||||||
|
Type: "aws_instance",
|
||||||
|
Primary: &InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Provider: "provider.aws.baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: m,
|
||||||
|
ProviderResolver: ResourceProviderResolverFixed(
|
||||||
|
map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
State: s,
|
||||||
|
})
|
||||||
|
|
||||||
|
expected := strings.TrimSpace(`
|
||||||
|
aws_instance.bar:
|
||||||
|
ID = foo
|
||||||
|
provider = provider.aws.foo`)
|
||||||
|
|
||||||
|
state, err := ctx.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := state.String()
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ func TestNewContextState(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
||||||
|
t.Helper()
|
||||||
// Enable the shadow graph
|
// Enable the shadow graph
|
||||||
opts.Shadow = true
|
opts.Shadow = true
|
||||||
|
|
||||||
|
@ -360,6 +361,7 @@ func testProvisioner() *MockResourceProvisioner {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkStateString(t *testing.T, state *State, expected string) {
|
func checkStateString(t *testing.T, state *State, expected string) {
|
||||||
|
t.Helper()
|
||||||
actual := strings.TrimSpace(state.String())
|
actual := strings.TrimSpace(state.String())
|
||||||
expected = strings.TrimSpace(expected)
|
expected = strings.TrimSpace(expected)
|
||||||
|
|
||||||
|
@ -380,6 +382,7 @@ func resourceState(resourceType, resourceID string) *ResourceState {
|
||||||
// Test helper that gives a function 3 seconds to finish, assumes deadlock and
|
// Test helper that gives a function 3 seconds to finish, assumes deadlock and
|
||||||
// fails test if it does not.
|
// fails test if it does not.
|
||||||
func testCheckDeadlock(t *testing.T, f func()) {
|
func testCheckDeadlock(t *testing.T, f func()) {
|
||||||
|
t.Helper()
|
||||||
timeout := make(chan bool, 1)
|
timeout := make(chan bool, 1)
|
||||||
done := make(chan bool, 1)
|
done := make(chan bool, 1)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -413,15 +416,18 @@ root
|
||||||
const testContextRefreshModuleStr = `
|
const testContextRefreshModuleStr = `
|
||||||
aws_instance.web: (tainted)
|
aws_instance.web: (tainted)
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.web:
|
aws_instance.web:
|
||||||
ID = new
|
ID = new
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testContextRefreshOutputStr = `
|
const testContextRefreshOutputStr = `
|
||||||
aws_instance.web:
|
aws_instance.web:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
|
@ -436,4 +442,5 @@ const testContextRefreshOutputPartialStr = `
|
||||||
const testContextRefreshTaintedStr = `
|
const testContextRefreshTaintedStr = `
|
||||||
aws_instance.web: (tainted)
|
aws_instance.web: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
|
@ -262,13 +262,8 @@ func (ctx *BuiltinEvalContext) InterpolateProvider(
|
||||||
var cfg *config.RawConfig
|
var cfg *config.RawConfig
|
||||||
|
|
||||||
if pc != nil && pc.RawConfig != nil {
|
if pc != nil && pc.RawConfig != nil {
|
||||||
path := pc.Path
|
|
||||||
if len(path) == 0 {
|
|
||||||
path = ctx.Path()
|
|
||||||
}
|
|
||||||
|
|
||||||
scope := &InterpolationScope{
|
scope := &InterpolationScope{
|
||||||
Path: path,
|
Path: ctx.Path(),
|
||||||
Resource: r,
|
Resource: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,13 +66,12 @@ func (w *ContextGraphWalker) EnterPath(path []string) EvalContext {
|
||||||
w.interpolaterVarLock.Unlock()
|
w.interpolaterVarLock.Unlock()
|
||||||
|
|
||||||
ctx := &BuiltinEvalContext{
|
ctx := &BuiltinEvalContext{
|
||||||
StopContext: w.StopContext,
|
StopContext: w.StopContext,
|
||||||
PathValue: path,
|
PathValue: path,
|
||||||
Hooks: w.Context.hooks,
|
Hooks: w.Context.hooks,
|
||||||
InputValue: w.Context.uiInput,
|
InputValue: w.Context.uiInput,
|
||||||
Components: w.Context.components,
|
Components: w.Context.components,
|
||||||
ProviderCache: w.providerCache,
|
ProviderCache: w.providerCache,
|
||||||
//ProviderConfigCache: w.providerConfigCache,
|
|
||||||
ProviderInputConfig: w.Context.providerInputConfig,
|
ProviderInputConfig: w.Context.providerInputConfig,
|
||||||
ProviderLock: &w.providerLock,
|
ProviderLock: &w.providerLock,
|
||||||
ProvisionerCache: w.provisionerCache,
|
ProvisionerCache: w.provisionerCache,
|
||||||
|
@ -150,7 +149,6 @@ func (w *ContextGraphWalker) ExitEvalTree(
|
||||||
func (w *ContextGraphWalker) init() {
|
func (w *ContextGraphWalker) init() {
|
||||||
w.contexts = make(map[string]*BuiltinEvalContext, 5)
|
w.contexts = make(map[string]*BuiltinEvalContext, 5)
|
||||||
w.providerCache = make(map[string]ResourceProvider, 5)
|
w.providerCache = make(map[string]ResourceProvider, 5)
|
||||||
//w.providerConfigCache = make(map[string]*ResourceConfig, 5)
|
|
||||||
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
|
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
|
||||||
w.interpolaterVars = make(map[string]map[string]interface{}, 5)
|
w.interpolaterVars = make(map[string]map[string]interface{}, 5)
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,9 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
|
||||||
// Get the state if we have it, if not we build it
|
// Get the state if we have it, if not we build it
|
||||||
rs := n.ResourceState
|
rs := n.ResourceState
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
rs = &ResourceState{}
|
rs = &ResourceState{
|
||||||
|
Provider: n.ResolvedProvider,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the config isn't empty we update the state
|
// If the config isn't empty we update the state
|
||||||
|
@ -146,7 +148,7 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
Provider: rs.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: rs.Dependencies,
|
Dependencies: rs.Dependencies,
|
||||||
State: &state, // state is nil here
|
State: &state, // state is nil here
|
||||||
},
|
},
|
||||||
|
@ -208,7 +210,7 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
Provider: rs.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: rs.Dependencies,
|
Dependencies: rs.Dependencies,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
|
@ -25,8 +26,13 @@ type NodeAbstractProvider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveProviderName(name string, path []string) string {
|
func ResolveProviderName(name string, path []string) string {
|
||||||
|
if strings.Contains(name, "provider.") {
|
||||||
|
// already resolved
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
name = fmt.Sprintf("provider.%s", name)
|
name = fmt.Sprintf("provider.%s", name)
|
||||||
if len(path) > 1 {
|
if len(path) >= 1 {
|
||||||
name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name)
|
name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (n *NodeApplyableResource) evalTreeDataResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -308,7 +308,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -332,7 +332,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
||||||
Else: &EvalWriteState{
|
Else: &EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,7 +149,9 @@ func (n *NodeDestroyResource) EvalTree() EvalNode {
|
||||||
// Get our state
|
// Get our state
|
||||||
rs := n.ResourceState
|
rs := n.ResourceState
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
rs = &ResourceState{}
|
rs = &ResourceState{
|
||||||
|
Provider: n.ResolvedProvider,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var diffApply *InstanceDiff
|
var diffApply *InstanceDiff
|
||||||
|
@ -273,7 +275,7 @@ func (n *NodeDestroyResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Addr.Type,
|
ResourceType: n.Addr.Type,
|
||||||
Provider: rs.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: rs.Dependencies,
|
Dependencies: rs.Dependencies,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -112,7 +112,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -177,7 +177,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -166,7 +166,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.ResourceState.Type,
|
ResourceType: n.ResourceState.Type,
|
||||||
Provider: n.ResourceState.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: n.ResourceState.Dependencies,
|
Dependencies: n.ResourceState.Dependencies,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -251,7 +251,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateID,
|
Name: stateID,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -220,11 +220,13 @@ func (h *HookRecordApplyOrder) PreApply(
|
||||||
const testTerraformInputProviderStr = `
|
const testTerraformInputProviderStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = override
|
bar = override
|
||||||
foo = us-east-1
|
foo = us-east-1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = baz
|
bar = baz
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -233,6 +235,7 @@ aws_instance.foo:
|
||||||
const testTerraformInputProviderOnlyStr = `
|
const testTerraformInputProviderOnlyStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = us-west-2
|
foo = us-west-2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -240,6 +243,7 @@ aws_instance.foo:
|
||||||
const testTerraformInputVarOnlyStr = `
|
const testTerraformInputVarOnlyStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = us-east-1
|
foo = us-east-1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -247,6 +251,7 @@ aws_instance.foo:
|
||||||
const testTerraformInputVarOnlyUnsetStr = `
|
const testTerraformInputVarOnlyUnsetStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = baz
|
bar = baz
|
||||||
foo = foovalue
|
foo = foovalue
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -255,11 +260,13 @@ aws_instance.foo:
|
||||||
const testTerraformInputVarsStr = `
|
const testTerraformInputVarsStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = override
|
bar = override
|
||||||
foo = us-east-1
|
foo = us-east-1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = baz
|
bar = baz
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -268,10 +275,12 @@ aws_instance.foo:
|
||||||
const testTerraformApplyStr = `
|
const testTerraformApplyStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -279,11 +288,13 @@ aws_instance.foo:
|
||||||
const testTerraformApplyDataBasicStr = `
|
const testTerraformApplyDataBasicStr = `
|
||||||
data.null_data_source.testing:
|
data.null_data_source.testing:
|
||||||
ID = yo
|
ID = yo
|
||||||
|
provider = provider.null
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyRefCountStr = `
|
const testTerraformApplyRefCountStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = 3
|
foo = 3
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -291,20 +302,24 @@ aws_instance.bar:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.2:
|
aws_instance.foo.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProviderAliasStr = `
|
const testTerraformApplyProviderAliasStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws.bar
|
provider = provider.aws.bar
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -312,9 +327,10 @@ aws_instance.foo:
|
||||||
const testTerraformApplyProviderAliasConfigStr = `
|
const testTerraformApplyProviderAliasConfigStr = `
|
||||||
another_instance.bar:
|
another_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = another.two
|
provider = provider.another.two
|
||||||
another_instance.foo:
|
another_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.another
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyEmptyModuleStr = `
|
const testTerraformApplyEmptyModuleStr = `
|
||||||
|
@ -335,6 +351,7 @@ aws_secret_key = ZZZZ
|
||||||
const testTerraformApplyDependsCreateBeforeStr = `
|
const testTerraformApplyDependsCreateBeforeStr = `
|
||||||
aws_instance.lb:
|
aws_instance.lb:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
instance = foo
|
instance = foo
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -342,6 +359,7 @@ aws_instance.lb:
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
aws_instance.web:
|
aws_instance.web:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
require_new = ami-new
|
require_new = ami-new
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -349,6 +367,7 @@ aws_instance.web:
|
||||||
const testTerraformApplyCreateBeforeStr = `
|
const testTerraformApplyCreateBeforeStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
require_new = xyz
|
require_new = xyz
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -356,6 +375,7 @@ aws_instance.bar:
|
||||||
const testTerraformApplyCreateBeforeUpdateStr = `
|
const testTerraformApplyCreateBeforeUpdateStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = baz
|
foo = baz
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -363,12 +383,14 @@ aws_instance.bar:
|
||||||
const testTerraformApplyCancelStr = `
|
const testTerraformApplyCancelStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyComputeStr = `
|
const testTerraformApplyComputeStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = computed_dynamical
|
foo = computed_dynamical
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -376,6 +398,7 @@ aws_instance.bar:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
dynamical = computed_dynamical
|
dynamical = computed_dynamical
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -429,10 +452,12 @@ const testTerraformApplyCountTaintedStr = `
|
||||||
const testTerraformApplyCountVariableStr = `
|
const testTerraformApplyCountVariableStr = `
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -440,6 +465,7 @@ aws_instance.foo.1:
|
||||||
const testTerraformApplyCountVariableRefStr = `
|
const testTerraformApplyCountVariableRefStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = 2
|
foo = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -447,30 +473,37 @@ aws_instance.bar:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyMinimalStr = `
|
const testTerraformApplyMinimalStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleStr = `
|
const testTerraformApplyModuleStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.baz:
|
aws_instance.baz:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -478,6 +511,7 @@ module.child:
|
||||||
const testTerraformApplyModuleBoolStr = `
|
const testTerraformApplyModuleBoolStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = 1
|
foo = 1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -500,10 +534,12 @@ module.child:
|
||||||
const testTerraformApplyMultiProviderStr = `
|
const testTerraformApplyMultiProviderStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
do_instance.foo:
|
do_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.do
|
||||||
num = 2
|
num = 2
|
||||||
type = do_instance
|
type = do_instance
|
||||||
`
|
`
|
||||||
|
@ -513,8 +549,10 @@ const testTerraformApplyModuleOnlyProviderStr = `
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.test
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleProviderAliasStr = `
|
const testTerraformApplyModuleProviderAliasStr = `
|
||||||
|
@ -522,7 +560,7 @@ const testTerraformApplyModuleProviderAliasStr = `
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = aws.eu
|
provider = module.child.provider.aws.eu
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleVarRefExistingStr = `
|
const testTerraformApplyModuleVarRefExistingStr = `
|
||||||
|
@ -533,6 +571,7 @@ aws_instance.foo:
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
value = bar
|
value = bar
|
||||||
`
|
`
|
||||||
|
@ -555,11 +594,13 @@ module.child:
|
||||||
const testTerraformApplyProvisionerStr = `
|
const testTerraformApplyProvisionerStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
dynamical = computed_dynamical
|
dynamical = computed_dynamical
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -570,13 +611,16 @@ const testTerraformApplyProvisionerModuleStr = `
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProvisionerFailStr = `
|
const testTerraformApplyProvisionerFailStr = `
|
||||||
aws_instance.bar: (tainted)
|
aws_instance.bar: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -584,6 +628,7 @@ aws_instance.foo:
|
||||||
const testTerraformApplyProvisionerFailCreateStr = `
|
const testTerraformApplyProvisionerFailCreateStr = `
|
||||||
aws_instance.bar: (tainted)
|
aws_instance.bar: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProvisionerFailCreateNoIdStr = `
|
const testTerraformApplyProvisionerFailCreateNoIdStr = `
|
||||||
|
@ -593,6 +638,7 @@ const testTerraformApplyProvisionerFailCreateNoIdStr = `
|
||||||
const testTerraformApplyProvisionerFailCreateBeforeDestroyStr = `
|
const testTerraformApplyProvisionerFailCreateBeforeDestroyStr = `
|
||||||
aws_instance.bar: (1 deposed)
|
aws_instance.bar: (1 deposed)
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
require_new = abc
|
require_new = abc
|
||||||
Deposed ID 1 = foo (tainted)
|
Deposed ID 1 = foo (tainted)
|
||||||
`
|
`
|
||||||
|
@ -600,6 +646,7 @@ aws_instance.bar: (1 deposed)
|
||||||
const testTerraformApplyProvisionerResourceRefStr = `
|
const testTerraformApplyProvisionerResourceRefStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -607,6 +654,7 @@ aws_instance.bar:
|
||||||
const testTerraformApplyProvisionerSelfRefStr = `
|
const testTerraformApplyProvisionerSelfRefStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -614,14 +662,17 @@ aws_instance.foo:
|
||||||
const testTerraformApplyProvisionerMultiSelfRefStr = `
|
const testTerraformApplyProvisionerMultiSelfRefStr = `
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 0
|
foo = number 0
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 1
|
foo = number 1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo.2:
|
aws_instance.foo.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 2
|
foo = number 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -629,10 +680,12 @@ aws_instance.foo.2:
|
||||||
const testTerraformApplyProvisionerMultiSelfRefSingleStr = `
|
const testTerraformApplyProvisionerMultiSelfRefSingleStr = `
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 0
|
foo = number 0
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 1
|
foo = number 1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -640,6 +693,7 @@ aws_instance.foo.1:
|
||||||
aws_instance.foo.0
|
aws_instance.foo.0
|
||||||
aws_instance.foo.2:
|
aws_instance.foo.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = number 2
|
foo = number 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -650,6 +704,7 @@ aws_instance.foo.2:
|
||||||
const testTerraformApplyProvisionerDiffStr = `
|
const testTerraformApplyProvisionerDiffStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -666,40 +721,47 @@ module.child.subchild:
|
||||||
const testTerraformApplyErrorStr = `
|
const testTerraformApplyErrorStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyErrorCreateBeforeDestroyStr = `
|
const testTerraformApplyErrorCreateBeforeDestroyStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
require_new = abc
|
require_new = abc
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = `
|
const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = `
|
||||||
aws_instance.bar: (1 deposed)
|
aws_instance.bar: (1 deposed)
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
Deposed ID 1 = bar
|
Deposed ID 1 = bar
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyErrorPartialStr = `
|
const testTerraformApplyErrorPartialStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyResourceDependsOnModuleStr = `
|
const testTerraformApplyResourceDependsOnModuleStr = `
|
||||||
aws_instance.a:
|
aws_instance.a:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
module.child
|
module.child
|
||||||
|
@ -707,11 +769,13 @@ aws_instance.a:
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.child:
|
aws_instance.child:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyResourceDependsOnModuleDeepStr = `
|
const testTerraformApplyResourceDependsOnModuleDeepStr = `
|
||||||
aws_instance.a:
|
aws_instance.a:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
module.child
|
module.child
|
||||||
|
@ -719,6 +783,7 @@ aws_instance.a:
|
||||||
module.child.grandchild:
|
module.child.grandchild:
|
||||||
aws_instance.c:
|
aws_instance.c:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyResourceDependsOnModuleInModuleStr = `
|
const testTerraformApplyResourceDependsOnModuleInModuleStr = `
|
||||||
|
@ -726,17 +791,20 @@ const testTerraformApplyResourceDependsOnModuleInModuleStr = `
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.b:
|
aws_instance.b:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
module.grandchild
|
module.grandchild
|
||||||
module.child.grandchild:
|
module.child.grandchild:
|
||||||
aws_instance.c:
|
aws_instance.c:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyTaintStr = `
|
const testTerraformApplyTaintStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -744,6 +812,7 @@ aws_instance.bar:
|
||||||
const testTerraformApplyTaintDepStr = `
|
const testTerraformApplyTaintDepStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -752,6 +821,7 @@ aws_instance.bar:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -759,6 +829,7 @@ aws_instance.foo:
|
||||||
const testTerraformApplyTaintDepRequireNewStr = `
|
const testTerraformApplyTaintDepRequireNewStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo
|
foo = foo
|
||||||
require_new = yes
|
require_new = yes
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
@ -767,6 +838,7 @@ aws_instance.bar:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -774,10 +846,12 @@ aws_instance.foo:
|
||||||
const testTerraformApplyOutputStr = `
|
const testTerraformApplyOutputStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -789,10 +863,12 @@ foo_num = 2
|
||||||
const testTerraformApplyOutputAddStr = `
|
const testTerraformApplyOutputAddStr = `
|
||||||
aws_instance.test.0:
|
aws_instance.test.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo0
|
foo = foo0
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.test.1:
|
aws_instance.test.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = foo1
|
foo = foo1
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -805,18 +881,22 @@ secondOutput = foo1
|
||||||
const testTerraformApplyOutputListStr = `
|
const testTerraformApplyOutputListStr = `
|
||||||
aws_instance.bar.0:
|
aws_instance.bar.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.1:
|
aws_instance.bar.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.2:
|
aws_instance.bar.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -828,18 +908,22 @@ foo_num = [bar,bar,bar]
|
||||||
const testTerraformApplyOutputMultiStr = `
|
const testTerraformApplyOutputMultiStr = `
|
||||||
aws_instance.bar.0:
|
aws_instance.bar.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.1:
|
aws_instance.bar.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.2:
|
aws_instance.bar.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -851,18 +935,22 @@ foo_num = bar,bar,bar
|
||||||
const testTerraformApplyOutputMultiIndexStr = `
|
const testTerraformApplyOutputMultiIndexStr = `
|
||||||
aws_instance.bar.0:
|
aws_instance.bar.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.1:
|
aws_instance.bar.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.bar.2:
|
aws_instance.bar.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
foo = bar
|
foo = bar
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
|
|
||||||
|
@ -874,6 +962,7 @@ foo_num = bar
|
||||||
const testTerraformApplyUnknownAttrStr = `
|
const testTerraformApplyUnknownAttrStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
@ -881,12 +970,14 @@ aws_instance.foo:
|
||||||
const testTerraformApplyVarsStr = `
|
const testTerraformApplyVarsStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = foo
|
bar = foo
|
||||||
baz = override
|
baz = override
|
||||||
foo = us-west-2
|
foo = us-west-2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = baz
|
bar = baz
|
||||||
list = Hello,World
|
list = Hello,World
|
||||||
map = Baz,Foo,Hello
|
map = Baz,Foo,Hello
|
||||||
|
@ -897,6 +988,7 @@ aws_instance.foo:
|
||||||
const testTerraformApplyVarsEnvStr = `
|
const testTerraformApplyVarsEnvStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.aws
|
||||||
bar = Hello,World
|
bar = Hello,World
|
||||||
baz = Baz,Foo,Hello
|
baz = Baz,Foo,Hello
|
||||||
foo = baz
|
foo = baz
|
||||||
|
@ -1650,6 +1742,7 @@ STATE:
|
||||||
const testTerraformInputHCL = `
|
const testTerraformInputHCL = `
|
||||||
hcl_instance.hcltest:
|
hcl_instance.hcltest:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.hcl
|
||||||
bar.w = z
|
bar.w = z
|
||||||
bar.x = y
|
bar.x = y
|
||||||
foo.# = 2
|
foo.# = 2
|
||||||
|
@ -1661,6 +1754,7 @@ hcl_instance.hcltest:
|
||||||
const testTerraformRefreshDataRefDataStr = `
|
const testTerraformRefreshDataRefDataStr = `
|
||||||
data.null_data_source.bar:
|
data.null_data_source.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.null
|
||||||
bar = yes
|
bar = yes
|
||||||
type = null_data_source
|
type = null_data_source
|
||||||
|
|
||||||
|
@ -1668,6 +1762,7 @@ data.null_data_source.bar:
|
||||||
data.null_data_source.foo
|
data.null_data_source.foo
|
||||||
data.null_data_source.foo:
|
data.null_data_source.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
|
provider = provider.null
|
||||||
foo = yes
|
foo = yes
|
||||||
type = null_data_source
|
type = null_data_source
|
||||||
`
|
`
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// this is the provider that should actually be used by orphaned resources
|
||||||
|
provider "aws" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "mod" {
|
||||||
|
source = "./mod"
|
||||||
|
providers = {
|
||||||
|
"aws.foo" = "aws.bar"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// removed module configuration referencing aws.foo, which was passed in by the
|
||||||
|
// root module
|
|
@ -0,0 +1,7 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "baz"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "baz" {
|
||||||
|
provider = "aws.baz"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "grandchild" {
|
||||||
|
source = "./grandchild"
|
||||||
|
providers = {
|
||||||
|
"aws.baz" = "aws.bar"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
value = "config"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "child" {
|
||||||
|
source = "child"
|
||||||
|
providers = {
|
||||||
|
"aws.bar" = "aws.foo"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "thing" {
|
||||||
|
provider = "aws.bar"
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
value = "config"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "child" {
|
||||||
|
source = "child"
|
||||||
|
providers = {
|
||||||
|
"aws.bar" = "aws.foo"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
provider = "aws.foo"
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/config/module"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GraphNodeAttachProvider is an interface that must be implemented by nodes
|
// GraphNodeAttachProvider is an interface that must be implemented by nodes
|
||||||
|
@ -19,62 +16,3 @@ type GraphNodeAttachProvider interface {
|
||||||
// Sets the configuration
|
// Sets the configuration
|
||||||
AttachProvider(*config.ProviderConfig)
|
AttachProvider(*config.ProviderConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachProviderConfigTransformer goes through the graph and attaches
|
|
||||||
// provider configuration structures to nodes that implement the interfaces
|
|
||||||
// above.
|
|
||||||
//
|
|
||||||
// The attached configuration structures are directly from the configuration.
|
|
||||||
// If they're going to be modified, a copy should be made.
|
|
||||||
type AttachProviderConfigTransformer struct {
|
|
||||||
Module *module.Tree // Module is the root module for the config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *AttachProviderConfigTransformer) Transform(g *Graph) error {
|
|
||||||
if err := t.attachProviders(g); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *AttachProviderConfigTransformer) attachProviders(g *Graph) error {
|
|
||||||
// Go through and find GraphNodeAttachProvider
|
|
||||||
for _, v := range g.Vertices() {
|
|
||||||
// Only care about GraphNodeAttachProvider implementations
|
|
||||||
apn, ok := v.(GraphNodeAttachProvider)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine what we're looking for
|
|
||||||
path := normalizeModulePath(apn.Path())
|
|
||||||
path = path[1:]
|
|
||||||
name := apn.ProviderName()
|
|
||||||
log.Printf("[TRACE] Attach provider request: %#v %s", path, name)
|
|
||||||
|
|
||||||
// Get the configuration.
|
|
||||||
tree := t.Module.Child(path)
|
|
||||||
if tree == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the provider configs to find the matching config
|
|
||||||
for _, p := range tree.Config().ProviderConfigs {
|
|
||||||
// Build the name, which is "name.alias" if an alias exists
|
|
||||||
current := p.Name
|
|
||||||
if p.Alias != "" {
|
|
||||||
current += "." + p.Alias
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the configs match then attach!
|
|
||||||
if current == name {
|
|
||||||
log.Printf("[TRACE] Attaching provider config: %#v", p)
|
|
||||||
apn.AttachProvider(p)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -133,78 +133,3 @@ 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.ProviderName,
|
Provider: n.ResolvedProvider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
@ -157,7 +157,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.ProviderName,
|
Provider: n.ResolvedProvider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
|
|
@ -240,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.ProviderName),
|
Provider: n.ResolvedProvider,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/config/module"
|
"github.com/hashicorp/terraform/config/module"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
@ -18,10 +20,6 @@ func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, m
|
||||||
Providers: providers,
|
Providers: providers,
|
||||||
Concrete: concrete,
|
Concrete: concrete,
|
||||||
},
|
},
|
||||||
// Attach configuration to each provider instance
|
|
||||||
&AttachProviderConfigTransformer{
|
|
||||||
Module: mod,
|
|
||||||
},
|
|
||||||
// Add any remaining missing providers
|
// Add any remaining missing providers
|
||||||
&MissingProviderTransformer{
|
&MissingProviderTransformer{
|
||||||
Providers: providers,
|
Providers: providers,
|
||||||
|
@ -29,8 +27,8 @@ func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, m
|
||||||
},
|
},
|
||||||
// Connect the providers
|
// Connect the providers
|
||||||
&ProviderTransformer{},
|
&ProviderTransformer{},
|
||||||
// Disable unused providers
|
// Remove unused providers and proxies
|
||||||
&DisableProviderTransformer{},
|
&PruneProviderTransformer{},
|
||||||
// Connect provider to their parent provider nodes
|
// Connect provider to their parent provider nodes
|
||||||
&ParentProviderTransformer{},
|
&ParentProviderTransformer{},
|
||||||
)
|
)
|
||||||
|
@ -54,7 +52,8 @@ type GraphNodeCloseProvider interface {
|
||||||
|
|
||||||
// GraphNodeProviderConsumer is an interface that nodes that require
|
// GraphNodeProviderConsumer is an interface that nodes that require
|
||||||
// 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. This may be a provider by type, type.alias or a fully resolved
|
||||||
|
// provider name
|
||||||
type GraphNodeProviderConsumer interface {
|
type GraphNodeProviderConsumer interface {
|
||||||
ProvidedBy() string
|
ProvidedBy() string
|
||||||
// Set the resolved provider address for this resource.
|
// Set the resolved provider address for this resource.
|
||||||
|
@ -107,6 +106,13 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see if this in an inherited provider
|
||||||
|
if p, ok := target.(*graphNodeProxyProvider); ok {
|
||||||
|
g.Remove(p)
|
||||||
|
target = p.Target()
|
||||||
|
key = target.(GraphNodeProvider).Name()
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] resource %s using provider %s", dag.VertexName(pv), key)
|
log.Printf("[DEBUG] resource %s using provider %s", dag.VertexName(pv), key)
|
||||||
pv.SetProvider(key)
|
pv.SetProvider(key)
|
||||||
g.Connect(dag.BasicEdge(v, target))
|
g.Connect(dag.BasicEdge(v, target))
|
||||||
|
@ -122,7 +128,6 @@ 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 := make(map[string]*graphNodeCloseProvider)
|
cpm := make(map[string]*graphNodeCloseProvider)
|
||||||
|
@ -248,22 +253,29 @@ func (t *ParentProviderTransformer) Transform(g *Graph) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PruneProviderTransformer is a GraphTransformer that prunes all the
|
// PruneProviderTransformer removes any providers that are not actually used by
|
||||||
// providers that aren't needed from the graph. A provider is unneeded if
|
// anything, and provider proxies. This avoids the provider being initialized
|
||||||
// no resource or module is using that provider.
|
// and configured. This both saves resources but also avoids errors since
|
||||||
|
// configuration may imply initialization which may require auth.
|
||||||
type PruneProviderTransformer struct{}
|
type PruneProviderTransformer struct{}
|
||||||
|
|
||||||
func (t *PruneProviderTransformer) Transform(g *Graph) error {
|
func (t *PruneProviderTransformer) Transform(g *Graph) error {
|
||||||
for _, v := range g.Vertices() {
|
for _, v := range g.Vertices() {
|
||||||
// We only care about the providers
|
// We only care about providers
|
||||||
if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
|
pn, ok := v.(GraphNodeProvider)
|
||||||
|
if !ok || pn.ProviderName() == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Does anything depend on this? If not, then prune it.
|
|
||||||
if s := g.UpEdges(v); s.Len() == 0 {
|
// ProxyProviders will have up edges, but we're now done with them in the graph
|
||||||
if nv, ok := v.(dag.NamedVertex); ok {
|
if _, ok := v.(*graphNodeProxyProvider); ok {
|
||||||
log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
|
log.Printf("[DEBUG] pruning proxy provider %s", dag.VertexName(v))
|
||||||
}
|
g.Remove(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove providers with no dependencies.
|
||||||
|
if g.UpEdges(v).Len() == 0 {
|
||||||
|
log.Printf("[DEBUG] pruning unused provider %s", dag.VertexName(v))
|
||||||
g.Remove(v)
|
g.Remove(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,6 +286,11 @@ 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 {
|
||||||
|
if strings.Contains(k, "provider.") {
|
||||||
|
// this is already resolved
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
// we create a dummy provider to
|
// we create a dummy provider to
|
||||||
var path []string
|
var path []string
|
||||||
if sp, ok := v.(GraphNodeSubPath); ok {
|
if sp, ok := v.(GraphNodeSubPath); ok {
|
||||||
|
@ -349,21 +366,219 @@ func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// graphNodeProviderConsumerDummy is a struct that never enters the real
|
// graphNodeProxyProvider is a GraphNodeProvider implementation that is used to
|
||||||
// graph (though it could to no ill effect). It implements
|
// store the name and value of a provider node for inheritance between modules.
|
||||||
// GraphNodeProviderConsumer and GraphNodeSubpath as a way to force
|
// These nodes are only used to store the data while loading the provider
|
||||||
// certain transformations.
|
// configurations, and are removed after all the resources have been connected
|
||||||
type graphNodeProviderConsumerDummy struct {
|
// to their providers.
|
||||||
ProviderValue string
|
type graphNodeProxyProvider struct {
|
||||||
PathValue []string
|
nameValue string
|
||||||
|
path []string
|
||||||
|
target GraphNodeProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeProviderConsumerDummy) Path() []string {
|
func (n *graphNodeProxyProvider) ProviderName() string {
|
||||||
return n.PathValue
|
return n.Target().ProviderName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeProviderConsumerDummy) ProvidedBy() string {
|
func (n *graphNodeProxyProvider) Name() string {
|
||||||
return n.ProviderValue
|
return ResolveProviderName(n.nameValue, n.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeProviderConsumerDummy) SetProvider(string) {}
|
// find the concrete provider instance
|
||||||
|
func (n *graphNodeProxyProvider) Target() GraphNodeProvider {
|
||||||
|
switch t := n.target.(type) {
|
||||||
|
case *graphNodeProxyProvider:
|
||||||
|
return t.Target()
|
||||||
|
default:
|
||||||
|
return n.target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderConfigTransformer adds all provider nodes from the configuration and
|
||||||
|
// attaches the configs.
|
||||||
|
type ProviderConfigTransformer struct {
|
||||||
|
Providers []string
|
||||||
|
Concrete ConcreteProviderNodeFunc
|
||||||
|
|
||||||
|
// each provider node is stored here so that the proxy nodes can look up
|
||||||
|
// their targets by name.
|
||||||
|
providers map[string]GraphNodeProvider
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.providers = make(map[string]GraphNodeProvider)
|
||||||
|
|
||||||
|
// Start the transformation process
|
||||||
|
if err := t.transform(g, t.Module); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally attach the configs to the new nodes
|
||||||
|
return t.attachProviderConfigs(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
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...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all provider configs
|
||||||
|
for _, p := range conf.ProviderConfigs {
|
||||||
|
name := p.Name
|
||||||
|
if p.Alias != "" {
|
||||||
|
name += "." + p.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is an empty config placeholder to accept a provier from a
|
||||||
|
// parent module, add a proxy and continue.
|
||||||
|
if t.addProxyProvider(g, m, p, name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v := t.Concrete(&NodeAbstractProvider{
|
||||||
|
NameValue: name,
|
||||||
|
PathValue: path,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add it to the graph
|
||||||
|
g.Add(v)
|
||||||
|
t.providers[ResolveProviderName(name, path)] = v.(GraphNodeProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a ProxyProviderConfig if this was inherited from a parent module. Return
|
||||||
|
// whether the proxy was added to the graph or not.
|
||||||
|
func (t *ProviderConfigTransformer) addProxyProvider(g *Graph, m *module.Tree, pc *config.ProviderConfig, name string) bool {
|
||||||
|
path := m.Path()
|
||||||
|
|
||||||
|
// This isn't a proxy if there's a config, or we're at the root
|
||||||
|
if len(pc.RawConfig.RawMap()) > 0 || len(path) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
parentPath := path[:len(path)-1]
|
||||||
|
parent := t.Module.Child(parentPath)
|
||||||
|
if parent == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentCfg *config.Module
|
||||||
|
for _, mod := range parent.Config().Modules {
|
||||||
|
if mod.Name == m.Name() {
|
||||||
|
parentCfg = mod
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parentCfg == nil {
|
||||||
|
panic("immaculately conceived module " + m.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
parentProviderName, ok := parentCfg.Providers[name]
|
||||||
|
if !ok {
|
||||||
|
// this provider isn't listed in a parent module block, so we just have
|
||||||
|
// an empty config
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// the parent module is passing in a provider
|
||||||
|
fullParentName := ResolveProviderName(parentProviderName, parentPath)
|
||||||
|
parentProvider := t.providers[fullParentName]
|
||||||
|
|
||||||
|
if parentProvider == nil {
|
||||||
|
panic(fmt.Sprintf("missing provider %s in module %s", parentProviderName, m.Name()))
|
||||||
|
}
|
||||||
|
|
||||||
|
v := &graphNodeProxyProvider{
|
||||||
|
nameValue: name,
|
||||||
|
path: path,
|
||||||
|
target: parentProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add it to the graph
|
||||||
|
g.Add(v)
|
||||||
|
t.providers[ResolveProviderName(name, path)] = v
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
|
// Only care about GraphNodeAttachProvider implementations
|
||||||
|
apn, ok := v.(GraphNodeAttachProvider)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine what we're looking for
|
||||||
|
path := normalizeModulePath(apn.Path())[1:]
|
||||||
|
name := apn.ProviderName()
|
||||||
|
log.Printf("[TRACE] Attach provider request: %#v %s", path, name)
|
||||||
|
|
||||||
|
// Get the configuration.
|
||||||
|
tree := t.Module.Child(path)
|
||||||
|
if tree == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through the provider configs to find the matching config
|
||||||
|
for _, p := range tree.Config().ProviderConfigs {
|
||||||
|
// Build the name, which is "name.alias" if an alias exists
|
||||||
|
current := p.Name
|
||||||
|
if p.Alias != "" {
|
||||||
|
current += "." + p.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the configs match then attach!
|
||||||
|
if current == name {
|
||||||
|
log.Printf("[TRACE] Attaching provider config: %#v", p)
|
||||||
|
apn.AttachProvider(p)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package terraform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/dag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DisableProviderTransformer "disables" any providers that are not actually
|
|
||||||
// used by anything. This avoids the provider being initialized and configured.
|
|
||||||
// This both saves resources but also avoids errors since configuration
|
|
||||||
// may imply initialization which may require auth.
|
|
||||||
type DisableProviderTransformer struct{}
|
|
||||||
|
|
||||||
func (t *DisableProviderTransformer) Transform(g *Graph) error {
|
|
||||||
for _, v := range g.Vertices() {
|
|
||||||
// We only care about providers
|
|
||||||
pn, ok := v.(GraphNodeProvider)
|
|
||||||
if !ok || pn.ProviderName() == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have dependencies, then don't disable
|
|
||||||
if g.UpEdges(v).Len() > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the path
|
|
||||||
var path []string
|
|
||||||
if pn, ok := v.(GraphNodeSubPath); ok {
|
|
||||||
path = pn.Path()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the provider by replacing it with a "disabled" provider
|
|
||||||
disabled := &NodeDisabledProvider{
|
|
||||||
NodeAbstractProvider: &NodeAbstractProvider{
|
|
||||||
NameValue: pn.ProviderName(),
|
|
||||||
PathValue: path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if !g.Replace(v, disabled) {
|
|
||||||
panic(fmt.Sprintf(
|
|
||||||
"vertex disappeared from under us: %s",
|
|
||||||
dag.VertexName(v)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -445,6 +445,72 @@ func TestPruneProviderTransformer(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the child module resource is attached to the configured parent provider
|
||||||
|
func TestProviderConfigTransformer_parentProviders(t *testing.T) {
|
||||||
|
mod := testModule(t, "transform-provider-inherit")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
tf := &AttachResourceConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tf := TransformProviders([]string{"aws"}, concrete, mod)
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testTransformModuleProviderConfigStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the child module resource is attached to the configured grand-parent provider
|
||||||
|
func TestProviderConfigTransformer_grandparentProviders(t *testing.T) {
|
||||||
|
mod := testModule(t, "transform-provider-grandchild-inherit")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
tf := &AttachResourceConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tf := TransformProviders([]string{"aws"}, concrete, mod)
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testTransformModuleProviderGrandparentStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testTransformProviderBasicStr = `
|
const testTransformProviderBasicStr = `
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
provider.aws
|
provider.aws
|
||||||
|
@ -481,9 +547,7 @@ module.sub.module.subsub.bar_instance.two
|
||||||
module.sub.module.subsub.foo_instance.one
|
module.sub.module.subsub.foo_instance.one
|
||||||
module.sub.provider.foo
|
module.sub.provider.foo
|
||||||
module.sub.provider.foo
|
module.sub.provider.foo
|
||||||
provider.foo (disabled)
|
|
||||||
provider.bar
|
provider.bar
|
||||||
provider.foo (disabled)
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTransformMissingProviderModuleChildStr = `
|
const testTransformMissingProviderModuleChildStr = `
|
||||||
|
@ -545,3 +609,15 @@ provider.aws (close)
|
||||||
provider.aws
|
provider.aws
|
||||||
var.foo
|
var.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testTransformModuleProviderConfigStr = `
|
||||||
|
module.child.aws_instance.thing
|
||||||
|
provider.aws.foo
|
||||||
|
provider.aws.foo
|
||||||
|
`
|
||||||
|
|
||||||
|
const testTransformModuleProviderGrandparentStr = `
|
||||||
|
module.child.module.grandchild.aws_instance.baz
|
||||||
|
provider.aws.foo
|
||||||
|
provider.aws.foo
|
||||||
|
`
|
||||||
|
|
Loading…
Reference in New Issue