diff --git a/internal/backend/local/backend.go b/internal/backend/local/backend.go index f5d07b20f..dd6c9cc56 100644 --- a/internal/backend/local/backend.go +++ b/internal/backend/local/backend.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/command/views" "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/terraform" "github.com/hashicorp/terraform/internal/tfdiags" @@ -313,6 +314,7 @@ func (b *Local) Operation(ctx context.Context, op *backend.Operation) (*backend. // Do it go func() { + defer logging.PanicHandler() defer done() defer stop() defer cancel() diff --git a/internal/backend/local/backend_apply.go b/internal/backend/local/backend_apply.go index 5b143a74f..897c36e40 100644 --- a/internal/backend/local/backend_apply.go +++ b/internal/backend/local/backend_apply.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/command/views" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/states/statefile" @@ -156,6 +157,7 @@ func (b *Local) opApply( var applyDiags tfdiags.Diagnostics doneCh := make(chan struct{}) go func() { + defer logging.PanicHandler() defer close(doneCh) log.Printf("[INFO] backend/local: apply calling Apply") applyState, applyDiags = lr.Core.Apply(plan, lr.Config) diff --git a/internal/backend/local/backend_plan.go b/internal/backend/local/backend_plan.go index c721074b4..b27f98c68 100644 --- a/internal/backend/local/backend_plan.go +++ b/internal/backend/local/backend_plan.go @@ -6,6 +6,7 @@ import ( "log" "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/plans/planfile" "github.com/hashicorp/terraform/internal/states/statefile" @@ -79,6 +80,7 @@ func (b *Local) opPlan( var planDiags tfdiags.Diagnostics doneCh := make(chan struct{}) go func() { + defer logging.PanicHandler() defer close(doneCh) log.Printf("[INFO] backend/local: plan calling Plan") plan, planDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts) diff --git a/internal/backend/local/backend_refresh.go b/internal/backend/local/backend_refresh.go index ddbedaf19..8ce3b6aff 100644 --- a/internal/backend/local/backend_refresh.go +++ b/internal/backend/local/backend_refresh.go @@ -7,6 +7,7 @@ import ( "os" "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/tfdiags" @@ -77,6 +78,7 @@ func (b *Local) opRefresh( var refreshDiags tfdiags.Diagnostics doneCh := make(chan struct{}) go func() { + defer logging.PanicHandler() defer close(doneCh) newState, refreshDiags = lr.Core.Refresh(lr.Config, lr.InputState, lr.PlanOpts) log.Printf("[INFO] backend/local: refresh calling Refresh") diff --git a/internal/backend/remote/backend.go b/internal/backend/remote/backend.go index e427befa0..bc4c03175 100644 --- a/internal/backend/remote/backend.go +++ b/internal/backend/remote/backend.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-svchost/disco" "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/terraform" @@ -755,6 +756,7 @@ func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend // Do it. go func() { + defer logging.PanicHandler() defer done() defer stop() defer cancel() diff --git a/internal/backend/remote/backend_common.go b/internal/backend/remote/backend_common.go index 845402199..dc102f594 100644 --- a/internal/backend/remote/backend_common.go +++ b/internal/backend/remote/backend_common.go @@ -13,6 +13,7 @@ import ( tfe "github.com/hashicorp/go-tfe" "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/terraform" ) @@ -464,6 +465,8 @@ func (b *Remote) confirm(stopCtx context.Context, op *backend.Operation, opts *t result := make(chan error, 2) go func() { + defer logging.PanicHandler() + // Make sure we cancel doneCtx before we return // so the input command is also canceled. defer cancel() diff --git a/internal/backend/remote/backend_plan.go b/internal/backend/remote/backend_plan.go index 736c040b4..ca74d18b6 100644 --- a/internal/backend/remote/backend_plan.go +++ b/internal/backend/remote/backend_plan.go @@ -17,6 +17,7 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -319,6 +320,8 @@ in order to capture the filesystem context the remote workspace expects: // cancellable after that period, we attempt to cancel it. if lockTimeout := op.StateLocker.Timeout(); lockTimeout > 0 { go func() { + defer logging.PanicHandler() + select { case <-stopCtx.Done(): return diff --git a/internal/command/login.go b/internal/command/login.go index 4ede60ddb..6b1d8bddd 100644 --- a/internal/command/login.go +++ b/internal/command/login.go @@ -22,6 +22,7 @@ import ( "github.com/hashicorp/terraform-svchost/disco" "github.com/hashicorp/terraform/internal/command/cliconfig" "github.com/hashicorp/terraform/internal/httpclient" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/terraform" "github.com/hashicorp/terraform/internal/tfdiags" @@ -450,6 +451,7 @@ func (c *LoginCommand) interactiveGetTokenByCode(hostname svchost.Hostname, cred }), } go func() { + defer logging.PanicHandler() err := server.Serve(listener) if err != nil && err != http.ErrServerClosed { diags = diags.Append(tfdiags.Sourceless( diff --git a/internal/logging/panic.go b/internal/logging/panic.go index 207b3a444..9ae6252ca 100644 --- a/internal/logging/panic.go +++ b/internal/logging/panic.go @@ -12,7 +12,6 @@ import ( // This output is shown if a panic happens. const panicOutput = ` - !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!! Terraform crashed! This is always indicative of a bug within Terraform. @@ -24,11 +23,11 @@ shown below, and any additional information which may help replicate the issue. [1]: https://github.com/hashicorp/terraform/issues !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!! + ` -// PanicHandler is called to recover from an internal panic in Terraform, and -// is intended to replace the standard stack trace with a more user friendly -// error message. +// PanicHandler is called to recover from an internal panic in Terraform, and +// augments the standard stack trace with a more user friendly error message. // PanicHandler must be called as a defered function. func PanicHandler() { recovered := recover() diff --git a/internal/terraform/context.go b/internal/terraform/context.go index 2174b0fe0..115f62276 100644 --- a/internal/terraform/context.go +++ b/internal/terraform/context.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/provisioners" "github.com/hashicorp/terraform/internal/states" @@ -264,6 +265,8 @@ func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan s done := c.runContext.Done() go func() { + defer logging.PanicHandler() + defer close(wait) // Wait for a stop or completion select { diff --git a/internal/terraform/graph.go b/internal/terraform/graph.go index 3d09f329b..9e2f19553 100644 --- a/internal/terraform/graph.go +++ b/internal/terraform/graph.go @@ -4,6 +4,7 @@ import ( "log" "strings" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/internal/tfdiags" "github.com/hashicorp/terraform/internal/addrs" @@ -39,6 +40,10 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics { // Walk the graph. walkFn := func(v dag.Vertex) (diags tfdiags.Diagnostics) { + // the walkFn is called asynchronously, and needs to be recovered + // separately in the case of a panic. + defer logging.PanicHandler() + log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v) defer func() { diff --git a/main.go b/main.go index 99e2c58a3..da5dfd9c9 100644 --- a/main.go +++ b/main.go @@ -59,6 +59,8 @@ func main() { } func realMain() int { + defer logging.PanicHandler() + var err error tmpLogPath := os.Getenv(envTmpLogPath)