expansion resource and instance orphans
When a module instances is removed, we need to add both the instance and resource deletion nodes from that module.
This commit is contained in:
parent
7a26fcfe84
commit
8add45b076
|
@ -6176,13 +6176,15 @@ resource "aws_instance" "foo" {
|
|||
t.Fatal(diags.ErrWithWarnings())
|
||||
}
|
||||
|
||||
if len(plan.Changes.Resources) != 1 {
|
||||
t.Fatalf("expected 1 change, got %d", len(plan.Changes.Resources))
|
||||
expected := map[string]plans.Action{
|
||||
`module.mod[1].aws_instance.foo`: plans.Delete,
|
||||
`module.mod[0].aws_instance.foo`: plans.NoOp,
|
||||
}
|
||||
|
||||
for _, res := range plan.Changes.Resources {
|
||||
if res.Action != plans.Delete {
|
||||
t.Fatalf("expected Delete action, got: %s", res.Action)
|
||||
want := expected[res.Addr.String()]
|
||||
if res.Action != want {
|
||||
t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
|
|||
|
||||
// Add the count orphans. As these are orphaned refresh nodes, we add them
|
||||
// directly as NodeDestroyableDataResource.
|
||||
&OrphanResourceCountTransformer{
|
||||
&OrphanResourceInstanceCountTransformer{
|
||||
Concrete: concreteResourceDestroyable,
|
||||
Addr: n.Addr,
|
||||
InstanceAddrs: instanceAddrs,
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/lang"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
)
|
||||
|
||||
// nodeExpandApplyableResource handles the first layer of resource
|
||||
|
@ -36,13 +37,47 @@ func (n *nodeExpandApplyableResource) DynamicExpand(ctx EvalContext) (*Graph, er
|
|||
var g Graph
|
||||
|
||||
expander := ctx.InstanceExpander()
|
||||
for _, module := range expander.ExpandModule(n.Addr.Module) {
|
||||
moduleInstances := expander.ExpandModule(n.Addr.Module)
|
||||
var resources []addrs.AbsResource
|
||||
for _, module := range moduleInstances {
|
||||
resAddr := n.Addr.Resource.Absolute(module)
|
||||
resources = append(resources, resAddr)
|
||||
g.Add(&NodeApplyableResource{
|
||||
NodeAbstractResource: n.NodeAbstractResource,
|
||||
Addr: n.Addr.Resource.Absolute(module),
|
||||
})
|
||||
}
|
||||
|
||||
// Lock the state while we inspect it to find any resources orphaned by
|
||||
// changes in module expansion.
|
||||
state := ctx.State().Lock()
|
||||
defer ctx.State().Unlock()
|
||||
|
||||
var orphans []*states.Resource
|
||||
for _, res := range state.Resources(n.Addr) {
|
||||
found := false
|
||||
for _, m := range moduleInstances {
|
||||
if m.Equal(res.Addr.Module) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// Address form state was not found in the current config
|
||||
if !found {
|
||||
orphans = append(orphans, res)
|
||||
}
|
||||
}
|
||||
|
||||
for _, res := range orphans {
|
||||
// add the resource cleanup node to remove the resource from state
|
||||
cleanupNode := &NodeDestroyResource{
|
||||
NodeAbstractResource: NewNodeAbstractResource(res.Addr.Config()),
|
||||
Addr: res.Addr,
|
||||
}
|
||||
|
||||
g.Add(cleanupNode)
|
||||
}
|
||||
|
||||
return &g, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
|
@ -54,14 +55,63 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, er
|
|||
var g Graph
|
||||
|
||||
expander := ctx.InstanceExpander()
|
||||
for _, module := range expander.ExpandModule(n.Addr.Module) {
|
||||
var resources []addrs.AbsResource
|
||||
moduleInstances := expander.ExpandModule(n.Addr.Module)
|
||||
|
||||
// Add the current expanded resource to the graph
|
||||
for _, module := range moduleInstances {
|
||||
resAddr := n.Addr.Resource.Absolute(module)
|
||||
resources = append(resources, resAddr)
|
||||
g.Add(&NodePlannableResource{
|
||||
NodeAbstractResource: n.NodeAbstractResource,
|
||||
Addr: n.Addr.Resource.Absolute(module),
|
||||
Addr: resAddr,
|
||||
ForceCreateBeforeDestroy: n.ForceCreateBeforeDestroy,
|
||||
})
|
||||
}
|
||||
|
||||
// Lock the state while we inspect it
|
||||
state := ctx.State().Lock()
|
||||
defer ctx.State().Unlock()
|
||||
|
||||
var orphans []*states.Resource
|
||||
for _, res := range state.Resources(n.Addr) {
|
||||
found := false
|
||||
for _, m := range moduleInstances {
|
||||
if m.Equal(res.Addr.Module) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// Address form state was not found in the current config
|
||||
if !found {
|
||||
orphans = append(orphans, res)
|
||||
}
|
||||
}
|
||||
|
||||
// The concrete resource factory we'll use for orphans
|
||||
concreteResourceOrphan := func(a *NodeAbstractResourceInstance) *NodePlannableResourceInstanceOrphan {
|
||||
// Add the config and state since we don't do that via transforms
|
||||
a.Config = n.Config
|
||||
a.ResolvedProvider = n.ResolvedProvider
|
||||
a.Schema = n.Schema
|
||||
a.ProvisionerSchemas = n.ProvisionerSchemas
|
||||
a.ProviderMetas = n.ProviderMetas
|
||||
|
||||
return &NodePlannableResourceInstanceOrphan{
|
||||
NodeAbstractResourceInstance: a,
|
||||
}
|
||||
}
|
||||
|
||||
for _, res := range orphans {
|
||||
for key := range res.Instances {
|
||||
addr := res.Addr.Instance(key)
|
||||
abs := NewNodeAbstractResourceInstance(addr)
|
||||
abs.AttachResourceState(res)
|
||||
n := concreteResourceOrphan(abs)
|
||||
g.Add(n)
|
||||
}
|
||||
}
|
||||
|
||||
return &g, nil
|
||||
}
|
||||
|
||||
|
@ -200,7 +250,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|||
},
|
||||
|
||||
// Add the count/for_each orphans
|
||||
&OrphanResourceCountTransformer{
|
||||
&OrphanResourceInstanceCountTransformer{
|
||||
Concrete: concreteResourceOrphan,
|
||||
Addr: n.Addr,
|
||||
InstanceAddrs: instanceAddrs,
|
||||
|
|
|
@ -147,7 +147,7 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
|
|||
|
||||
// Add the count orphans to make sure these resources are accounted for
|
||||
// during a scale in.
|
||||
&OrphanResourceCountTransformer{
|
||||
&OrphanResourceInstanceCountTransformer{
|
||||
Concrete: concreteResource,
|
||||
Addr: n.Addr,
|
||||
InstanceAddrs: instanceAddrs,
|
||||
|
|
|
@ -8,14 +8,14 @@ import (
|
|||
"github.com/hashicorp/terraform/states"
|
||||
)
|
||||
|
||||
// OrphanResourceCountTransformer is a GraphTransformer that adds orphans
|
||||
// OrphanResourceInstanceCountTransformer is a GraphTransformer that adds orphans
|
||||
// for an expanded count to the graph. The determination of this depends
|
||||
// on the count argument given.
|
||||
//
|
||||
// Orphans are found by comparing the count to what is found in the state.
|
||||
// This transform assumes that if an element in the state is within the count
|
||||
// bounds given, that it is not an orphan.
|
||||
type OrphanResourceCountTransformer struct {
|
||||
type OrphanResourceInstanceCountTransformer struct {
|
||||
Concrete ConcreteResourceInstanceNodeFunc
|
||||
|
||||
Addr addrs.AbsResource // Addr of the resource to look for orphans
|
||||
|
@ -23,7 +23,7 @@ type OrphanResourceCountTransformer struct {
|
|||
State *states.State // Full global state
|
||||
}
|
||||
|
||||
func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
|
||||
func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error {
|
||||
rs := t.State.Resource(t.Addr)
|
||||
if rs == nil {
|
||||
return nil // Resource doesn't exist in state, so nothing to do!
|
||||
|
@ -47,7 +47,7 @@ Have:
|
|||
if f := t.Concrete; f != nil {
|
||||
node = f(abstract)
|
||||
}
|
||||
log.Printf("[TRACE] OrphanResourceCountTransformer: adding %s as %T", thisAddr, node)
|
||||
log.Printf("[TRACE] OrphanResourceInstanceCountTransformer: adding %s as %T", thisAddr, node)
|
||||
g.Add(node)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue