do not create delete change for nonexistent output (#31471)

If there are outputs in configuration, a destroy plan will always contain a "delete" change for each of these outputs.

This leads to meaningless delete changes being present for outputs which were not present in state and therefore cannot be deleted. Since there is a change in the plan, this plan will then be considered applyable, and the user will be presented with text instructing them to apply a plan in which there are no actual changes.

This commit stops the above from happening in the case of root module outputs.
pull/31573/head
kmoe 4 years ago committed by GitHub
parent a857084dfe
commit c4a00664d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -420,12 +420,14 @@ func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) tfdia
before := cty.NullVal(cty.DynamicPseudoType)
mod := state.Module(n.Addr.Module)
if n.Addr.Module.IsRoot() && mod != nil {
for name, o := range mod.OutputValues {
if name == n.Addr.OutputValue.Name {
sensitiveBefore = o.Sensitive
before = o.Value
break
}
if o, ok := mod.OutputValues[n.Addr.OutputValue.Name]; ok {
sensitiveBefore = o.Sensitive
before = o.Value
} else {
// If the output was not in state, a delete change would
// be meaningless, so exit early.
return nil
}
}

@ -5,11 +5,12 @@ import (
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/hashicorp/terraform/internal/states"
"github.com/zclconf/go-cty/cty"
)
func TestNodeApplyableOutputExecute_knownValue(t *testing.T) {
@ -160,3 +161,22 @@ func TestNodeDestroyableOutputExecute(t *testing.T) {
t.Fatal("Unexpected outputs in state after removal")
}
}
func TestNodeDestroyableOutputExecute_notInState(t *testing.T) {
outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)
state := states.NewState()
ctx := &MockEvalContext{
StateState: state.SyncWrapper(),
}
node := NodeDestroyableOutput{Addr: outputAddr}
diags := node.Execute(ctx, walkApply)
if diags.HasErrors() {
t.Fatalf("Unexpected error: %s", diags.Err())
}
if state.OutputValue(outputAddr) != nil {
t.Fatal("Unexpected outputs in state after removal")
}
}

Loading…
Cancel
Save