Merge pull request #19676 from hashicorp/jbardin/ResourceInstanceObject

Ensure we have providers when scaling in counted data sources
This commit is contained in:
James Bardin 2018-12-18 13:23:59 -05:00 committed by GitHub
commit 7ce03b5a7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 13 deletions

View File

@ -179,7 +179,7 @@ func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen G
if inst == nil { if inst == nil {
return nil return nil
} }
return inst.GetGeneration(gen) return inst.GetGeneration(gen).DeepCopy()
} }
// SetResourceMeta updates the resource-level metadata for the resource at // SetResourceMeta updates the resource-level metadata for the resource at

View File

@ -212,6 +212,10 @@ func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
absAddr := n.Addr.Absolute(ctx.Path()) absAddr := n.Addr.Absolute(ctx.Path())
state := ctx.State() state := ctx.State()
if n.ProviderAddr.ProviderConfig.Type == "" {
return nil, fmt.Errorf("failed to write state for %s, missing provider type", absAddr)
}
obj := *n.State obj := *n.State
if obj == nil || obj.Value.IsNull() { if obj == nil || obj.Value.IsNull() {
// No need to encode anything: we'll just write it directly. // No need to encode anything: we'll just write it directly.

View File

@ -1,23 +1,40 @@
package terraform package terraform
import ( import (
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/states"
) )
// NodeDestroyableDataResource represents a resource that is "destroyable": // NodeDestroyableDataResourceInstance represents a resource that is "destroyable":
// it is ready to be destroyed. // it is ready to be destroyed.
type NodeDestroyableDataResource struct { type NodeDestroyableDataResourceInstance struct {
*NodeAbstractResourceInstance *NodeAbstractResourceInstance
} }
// GraphNodeEvalable // GraphNodeEvalable
func (n *NodeDestroyableDataResource) EvalTree() EvalNode { func (n *NodeDestroyableDataResourceInstance) EvalTree() EvalNode {
addr := n.ResourceInstanceAddr() addr := n.ResourceInstanceAddr()
var providerSchema *ProviderSchema
// We don't need the provider, but we're calling EvalGetProvider to load the
// schema.
var provider providers.Interface
// Just destroy it. // Just destroy it.
var state *states.ResourceInstanceObject var state *states.ResourceInstanceObject
return &EvalWriteState{ return &EvalSequence{
Addr: addr.Resource, Nodes: []EvalNode{
State: &state, // state is nil here &EvalGetProvider{
Addr: n.ResolvedProvider,
Output: &provider,
Schema: &providerSchema,
},
&EvalWriteState{
Addr: addr.Resource,
State: &state,
ProviderAddr: n.ResolvedProvider,
ProviderSchema: &providerSchema,
},
},
} }
} }

View File

@ -56,10 +56,11 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
// We also need a destroyable resource for orphans that are a result of a // We also need a destroyable resource for orphans that are a result of a
// scaled-in count. // scaled-in count.
concreteResourceDestroyable := func(a *NodeAbstractResourceInstance) dag.Vertex { concreteResourceDestroyable := func(a *NodeAbstractResourceInstance) dag.Vertex {
// Add the config since we don't do that via transforms // Add the config and provider since we don't do that via transforms
a.Config = n.Config a.Config = n.Config
a.ResolvedProvider = n.ResolvedProvider
return &NodeDestroyableDataResource{ return &NodeDestroyableDataResourceInstance{
NodeAbstractResourceInstance: a, NodeAbstractResourceInstance: a,
} }
} }

View File

@ -128,6 +128,11 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleIn(t *testing.T) {
"foo", "foo",
), ),
Config: m.Module.DataResources["data.aws_instance.foo"], Config: m.Module.DataResources["data.aws_instance.foo"],
ResolvedProvider: addrs.AbsProviderConfig{
ProviderConfig: addrs.ProviderConfig{
Type: "aws",
},
},
}, },
} }
@ -147,14 +152,29 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleIn(t *testing.T) {
expected := `data.aws_instance.foo[0] - *terraform.NodeRefreshableDataResourceInstance expected := `data.aws_instance.foo[0] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[1] - *terraform.NodeRefreshableDataResourceInstance data.aws_instance.foo[1] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[2] - *terraform.NodeRefreshableDataResourceInstance data.aws_instance.foo[2] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[3] - *terraform.NodeDestroyableDataResource data.aws_instance.foo[3] - *terraform.NodeDestroyableDataResourceInstance
root - terraform.graphNodeRoot root - terraform.graphNodeRoot
data.aws_instance.foo[0] - *terraform.NodeRefreshableDataResourceInstance data.aws_instance.foo[0] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[1] - *terraform.NodeRefreshableDataResourceInstance data.aws_instance.foo[1] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[2] - *terraform.NodeRefreshableDataResourceInstance data.aws_instance.foo[2] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[3] - *terraform.NodeDestroyableDataResource data.aws_instance.foo[3] - *terraform.NodeDestroyableDataResourceInstance
` `
if expected != actual { if expected != actual {
t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual) t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual)
} }
var destroyableDataResource *NodeDestroyableDataResourceInstance
for _, v := range g.Vertices() {
if r, ok := v.(*NodeDestroyableDataResourceInstance); ok {
destroyableDataResource = r
}
}
if destroyableDataResource == nil {
t.Fatal("failed to find a destroyableDataResource")
}
if destroyableDataResource.ResolvedProvider.ProviderConfig.Type == "" {
t.Fatal("NodeDestroyableDataResourceInstance missing provider config")
}
} }

View File

@ -149,7 +149,7 @@ func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
NodeAbstractResourceInstance: n.NodeAbstractResourceInstance, NodeAbstractResourceInstance: n.NodeAbstractResourceInstance,
} }
} else { } else {
dn = &NodeDestroyableDataResource{ dn = &NodeDestroyableDataResourceInstance{
NodeAbstractResourceInstance: n.NodeAbstractResourceInstance, NodeAbstractResourceInstance: n.NodeAbstractResourceInstance,
} }
} }

View File

@ -59,7 +59,9 @@ func (t *AttachStateTransformer) Transform(g *Graph) error {
continue continue
} }
an.AttachResourceState(rs) // make sure to attach a copy of the state, so instances can modify the
// same ResourceState.
an.AttachResourceState(rs.DeepCopy())
} }
return nil return nil