Skip to content

Commit

Permalink
do not create delete change for nonexistent output (#31471)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kmoe committed Aug 3, 2022
1 parent a857084 commit c4a0066
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
14 changes: 8 additions & 6 deletions internal/terraform/node_output.go
Expand Up @@ -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

}
}

Expand Down
22 changes: 21 additions & 1 deletion internal/terraform/node_output_test.go
Expand Up @@ -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) {
Expand Down Expand Up @@ -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")
}
}

0 comments on commit c4a0066

Please sign in to comment.