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 {
return nil
}
return inst.GetGeneration(gen)
return inst.GetGeneration(gen).DeepCopy()
}
// 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())
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
if obj == nil || obj.Value.IsNull() {
// No need to encode anything: we'll just write it directly.

View File

@ -1,23 +1,40 @@
package terraform
import (
"github.com/hashicorp/terraform/providers"
"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.
type NodeDestroyableDataResource struct {
type NodeDestroyableDataResourceInstance struct {
*NodeAbstractResourceInstance
}
// GraphNodeEvalable
func (n *NodeDestroyableDataResource) EvalTree() EvalNode {
func (n *NodeDestroyableDataResourceInstance) EvalTree() EvalNode {
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.
var state *states.ResourceInstanceObject
return &EvalWriteState{
Addr: addr.Resource,
State: &state, // state is nil here
return &EvalSequence{
Nodes: []EvalNode{
&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
// scaled-in count.
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.ResolvedProvider = n.ResolvedProvider
return &NodeDestroyableDataResource{
return &NodeDestroyableDataResourceInstance{
NodeAbstractResourceInstance: a,
}
}

View File

@ -128,6 +128,11 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleIn(t *testing.T) {
"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
data.aws_instance.foo[1] - *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
data.aws_instance.foo[0] - *terraform.NodeRefreshableDataResourceInstance
data.aws_instance.foo[1] - *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 {
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,
}
} else {
dn = &NodeDestroyableDataResource{
dn = &NodeDestroyableDataResourceInstance{
NodeAbstractResourceInstance: n.NodeAbstractResourceInstance,
}
}

View File

@ -59,7 +59,9 @@ func (t *AttachStateTransformer) Transform(g *Graph) error {
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