mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
get rid of EvalEarlyExitError
This was mostly unused now, since we no longer needed to interrupt a series of eval node executions. The exception was the stopHook, which is still used to halt execution when there's an interrupt. Since interrupting execution should not complete successfully, we use a normal opaque error to halt everything, and return it to the UI. We can work on coalescing or hiding these if necessary in a separate PR.
This commit is contained in:
parent
988059d533
commit
95f30451d9
@ -1734,8 +1734,16 @@ func TestContext2Apply_cancel(t *testing.T) {
|
||||
}()
|
||||
|
||||
state := <-stateCh
|
||||
if applyDiags.HasErrors() {
|
||||
t.Fatalf("unexpected errors: %s", applyDiags.Err())
|
||||
// only expecting an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(state.String())
|
||||
@ -1812,8 +1820,16 @@ func TestContext2Apply_cancelBlock(t *testing.T) {
|
||||
|
||||
// Wait for apply to complete
|
||||
state := <-stateCh
|
||||
if applyDiags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", applyDiags.Err())
|
||||
// only expecting an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
@ -1882,7 +1898,18 @@ func TestContext2Apply_cancelProvisioner(t *testing.T) {
|
||||
|
||||
// Wait for completion
|
||||
state := <-stateCh
|
||||
assertNoErrors(t, applyDiags)
|
||||
|
||||
// we are expecting only an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
aws_instance.foo: (tainted)
|
||||
|
@ -107,7 +107,7 @@ func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
||||
case HookActionHalt:
|
||||
// Return an early exit error to trigger an early exit
|
||||
log.Printf("[WARN] Early exit triggered by hook: %T", h)
|
||||
return EvalEarlyExitError{}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
package terraform
|
||||
|
||||
// EvalEarlyExitError is a special error return value that can be returned
|
||||
// by eval nodes that does an early exit.
|
||||
type EvalEarlyExitError struct{}
|
||||
|
||||
func (EvalEarlyExitError) Error() string { return "early exit" }
|
@ -2,7 +2,6 @@ package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
@ -36,7 +35,6 @@ type ContextGraphWalker struct {
|
||||
// is in progress.
|
||||
NonFatalDiagnostics tfdiags.Diagnostics
|
||||
|
||||
errorLock sync.Mutex
|
||||
once sync.Once
|
||||
contexts map[string]*BuiltinEvalContext
|
||||
contextLock sync.Mutex
|
||||
@ -124,46 +122,7 @@ func (w *ContextGraphWalker) init() {
|
||||
func (w *ContextGraphWalker) Execute(ctx EvalContext, n GraphNodeExecutable) tfdiags.Diagnostics {
|
||||
// Acquire a lock on the semaphore
|
||||
w.Context.parallelSem.Acquire()
|
||||
defer w.Context.parallelSem.Release()
|
||||
|
||||
diags := n.Execute(ctx, w.Operation)
|
||||
|
||||
// Release the semaphore
|
||||
w.Context.parallelSem.Release()
|
||||
|
||||
if !diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Acquire the lock because anything is going to require a lock.
|
||||
w.errorLock.Lock()
|
||||
defer w.errorLock.Unlock()
|
||||
|
||||
err := diags.Err()
|
||||
// Handle a simple early exit error
|
||||
if errors.Is(err, EvalEarlyExitError{}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// we need to see if this wraps only EarlyExitErrors
|
||||
if wrapper, ok := err.(interface{ WrappedErrors() []error }); ok {
|
||||
//WrappedErrors only returns native error values, so we can't extract
|
||||
//them from diagnostics. Just return the whole thing if we have a
|
||||
//combination.
|
||||
errs := wrapper.WrappedErrors()
|
||||
earlyExit := true
|
||||
for _, err := range errs {
|
||||
if err != (EvalEarlyExitError{}) {
|
||||
earlyExit = false
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 && earlyExit {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we'll let our usual diagnostics machinery figure out how to
|
||||
// unpack this as one or more diagnostic messages and return that. If we
|
||||
// get down here then the returned diagnostics will contain at least one
|
||||
// error, causing the graph walk to halt.
|
||||
return diags
|
||||
return n.Execute(ctx, w.Operation)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
@ -76,11 +77,7 @@ func (h *stopHook) PostStateUpdate(new *states.State) (HookAction, error) {
|
||||
|
||||
func (h *stopHook) hook() (HookAction, error) {
|
||||
if h.Stopped() {
|
||||
// FIXME: This should really return an error since stopping partway
|
||||
// through is not a successful run-to-completion, but we'll need to
|
||||
// introduce that cautiously since existing automation solutions may
|
||||
// be depending on this behavior.
|
||||
return HookActionHalt, nil
|
||||
return HookActionHalt, errors.New("execution halted")
|
||||
}
|
||||
|
||||
return HookActionContinue, nil
|
||||
|
@ -148,7 +148,6 @@ func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (di
|
||||
}
|
||||
// Stop early if we don't actually have a diff
|
||||
if change == nil {
|
||||
diags = diags.Append(EvalEarlyExitError{})
|
||||
return diags
|
||||
}
|
||||
|
||||
@ -223,7 +222,6 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
// We don't want to do any destroys
|
||||
// (these are handled by NodeDestroyResourceInstance instead)
|
||||
if diffApply == nil || diffApply.Action == plans.Delete {
|
||||
diags = diags.Append(EvalEarlyExitError{})
|
||||
return diags
|
||||
}
|
||||
|
||||
@ -325,7 +323,6 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
// into a NoOp if it only requires destroying, since destroying
|
||||
// is handled by NodeDestroyResourceInstance.
|
||||
if diffApply == nil || diffApply.Action == plans.NoOp {
|
||||
diags = diags.Append(EvalEarlyExitError{})
|
||||
return diags
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,6 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
||||
// EvalReduceDiff may have simplified our planned change
|
||||
// into a NoOp if it does not require destroying.
|
||||
if changeApply == nil || changeApply.Action == plans.NoOp {
|
||||
diags = diags.Append(EvalEarlyExitError{})
|
||||
return diags
|
||||
}
|
||||
|
||||
@ -175,7 +174,6 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
||||
|
||||
// Exit early if the state object is null after reading the state
|
||||
if state == nil || state.Value.IsNull() {
|
||||
diags = diags.Append(EvalEarlyExitError{})
|
||||
return diags
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user