terraform: orphaned grandchild module inherits provider config

This fixes an issue where orphaned grandchild modules don't properly
inherit their provider configurations from grandparents. I found this
while working on shadow graphs (the shadow graph actually caught an
inconsistency between runs and exposed this bug!), so I'm unsure if this
affects any issue.

To better explain the issue, I'll diagram things.

Here is a hierarchy that _works_ (w/o this PR):

```
root
|-- child1 (orphan)
|-- child2
    |-- grandchild
```

All modules in this case will successfully inherit provider
configurations from "root".

Here is a hierarchy that _doesn't work without this PR_:

```
root
|-- child1 (orphan)
    |-- grandchild (orphan)
```

In this case, `child1` does successfully inherit the provider from root,
but `grandchild` _will not_ unless `child1` had resources. If `child1`
has no resources, it wouldn't inherit anything. This PR fixes that.
This commit is contained in:
Mitchell Hashimoto 2016-10-11 15:51:27 +08:00
parent 258005408b
commit 8c9097f454
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 52 additions and 3 deletions

View File

@ -1390,6 +1390,54 @@ func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
} }
} }
func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
m := testModule(t, "apply-module-orphan-provider-inherit")
p := testProvider("aws")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
p.ConfigureFn = func(c *ResourceConfig) error {
if _, ok := c.Get("value"); !ok {
return fmt.Errorf("value is not found")
}
return nil
}
// Create a state with an orphan module that is nested (grandchild)
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: []string{"root", "parent", "child"},
Resources: map[string]*ResourceState{
"aws_instance.bar": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
},
},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Module: m,
State: state,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
if _, err := ctx.Plan(); err != nil {
t.Fatalf("err: %s", err)
}
if _, err := ctx.Apply(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
m := testModule(t, "apply-module-grandchild-provider-inherit") m := testModule(t, "apply-module-grandchild-provider-inherit")
p := testProvider("aws") p := testProvider("aws")

View File

@ -523,9 +523,10 @@ func (n *graphNodeProviderFlat) DependableName() []string {
func (n *graphNodeProviderFlat) DependentOn() []string { func (n *graphNodeProviderFlat) DependentOn() []string {
var result []string var result []string
// If we're in a module, then depend on our parent's provider // If we're in a module, then depend on all parent providers. Some of
if len(n.PathValue) > 1 { // these may not exist, hence we depend on all of them.
prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) for i := len(n.PathValue); i > 1; i-- {
prefix := modulePrefixStr(n.PathValue[:i-1])
result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix) result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix)
} }