Read orphaned resources during plan

This forces orphaned resources to be re-read during planning, removing
them from the state if they no longer exist.

This needs to be done for a bare `refresh` execution, since Terraform
should remove instances that don't exist and are not in the
configuration from the state. They should also be removed from state so
there is no Delete change planned, as not all providers will gracefully
handle a delete operation on a resource that does not exist.
This commit is contained in:
James Bardin 2020-10-22 09:13:02 -04:00
parent 2f091836c9
commit ddb2bbf4e9
2 changed files with 38 additions and 1 deletions

View File

@ -191,6 +191,7 @@ func (b *PlanGraphBuilder) init() {
b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex {
return &NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: a,
skipRefresh: b.skipRefresh,
}
}
}

View File

@ -9,6 +9,8 @@ import (
// it is ready to be applied and is represented by a diff.
type NodePlannableResourceInstanceOrphan struct {
*NodeAbstractResourceInstance
skipRefresh bool
}
var (
@ -35,7 +37,7 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOp
var change *plans.ResourceInstanceChange
var state *states.ResourceInstanceObject
_, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
if err != nil {
return err
}
@ -45,6 +47,40 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOp
return err
}
if !n.skipRefresh {
// Refresh this instance even though it is going to be destroyed, in
// order to catch missing resources. If this is a normal plan,
// providers expect a Read request to remove missing resources from the
// plan before apply, and may not handle a missing resource during
// Delete correctly. If this is a simple refresh, Terraform is
// expected to remove the missing resource from the state entirely
refresh := &EvalRefresh{
Addr: addr.Resource,
ProviderAddr: n.ResolvedProvider,
Provider: &provider,
ProviderMetas: n.ProviderMetas,
ProviderSchema: &providerSchema,
State: &state,
Output: &state,
}
_, err = refresh.Eval(ctx)
if err != nil {
return err
}
writeRefreshState := &EvalWriteState{
Addr: addr.Resource,
ProviderAddr: n.ResolvedProvider,
ProviderSchema: &providerSchema,
State: &state,
targetState: refreshState,
}
_, err = writeRefreshState.Eval(ctx)
if err != nil {
return err
}
}
diffDestroy := &EvalDiffDestroy{
Addr: addr.Resource,
State: &state,