Skip to content

Commit d429e82

Browse files
committed
command: show shadow errors to the user
1 parent 7291376 commit d429e82

4 files changed

Lines changed: 98 additions & 0 deletions

File tree

‎command/apply.go‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func (c *ApplyCommand) Run(args []string) int {
136136
}
137137
}
138138

139+
// This is going to keep track of shadow errors
140+
var shadowErr error
141+
139142
// Build the context based on the arguments given
140143
ctx, planned, err := c.Context(contextOpts{
141144
Destroy: c.Destroy,
@@ -189,6 +192,12 @@ func (c *ApplyCommand) Run(args []string) int {
189192
c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
190193
return 1
191194
}
195+
196+
// Record any shadow errors for later
197+
if err := ctx.ShadowError(); err != nil {
198+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
199+
err, "input operation:"))
200+
}
192201
}
193202
if !validateContext(ctx, c.Ui) {
194203
return 1
@@ -208,6 +217,12 @@ func (c *ApplyCommand) Run(args []string) int {
208217
"Error creating plan: %s", err))
209218
return 1
210219
}
220+
221+
// Record any shadow errors for later
222+
if err := ctx.ShadowError(); err != nil {
223+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
224+
err, "plan operation:"))
225+
}
211226
}
212227

213228
// Setup the state hook for continuous state updates
@@ -229,6 +244,12 @@ func (c *ApplyCommand) Run(args []string) int {
229244
go func() {
230245
defer close(doneCh)
231246
state, applyErr = ctx.Apply()
247+
248+
// Record any shadow errors for later
249+
if err := ctx.ShadowError(); err != nil {
250+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
251+
err, "apply operation:"))
252+
}
232253
}()
233254

234255
// Wait for the apply to finish or for us to be interrupted so
@@ -304,6 +325,9 @@ func (c *ApplyCommand) Run(args []string) int {
304325
}
305326
}
306327

328+
// If we have an error in the shadow graph, let the user know.
329+
c.outputShadowError(shadowErr, applyErr == nil)
330+
307331
return 0
308332
}
309333

‎command/meta.go‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,42 @@ func (m *Meta) addModuleDepthFlag(flags *flag.FlagSet, moduleDepth *int) {
460460
}
461461
}
462462

463+
// outputShadowError outputs the error from ctx.ShadowError. If the
464+
// error is nil then nothing happens. If output is false then it isn't
465+
// outputted to the user (you can define logic to guard against outputting).
466+
func (m *Meta) outputShadowError(err error, output bool) bool {
467+
// Do nothing if no error
468+
if err == nil {
469+
return false
470+
}
471+
472+
// If not outputting, do nothing
473+
if !output {
474+
return false
475+
}
476+
477+
// Output!
478+
m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
479+
"[reset][bold][yellow]\nExperimental feature failure! Please report a bug.\n\n"+
480+
"This is not an error. Your Terraform operation completed successfully.\n"+
481+
"Your real infrastructure is unaffected by this message.\n\n"+
482+
"[reset][yellow]While running, Terraform sometimes tests experimental features in the\n"+
483+
"background. These features cannot affect real state and never touch\n"+
484+
"real infrastructure. If the features work properly, you see nothing.\n"+
485+
"If the features fail, this message appears.\n\n"+
486+
"The following failures happened while running experimental features.\n"+
487+
"Please report a Terraform bug so that future Terraform versions that\n"+
488+
"enable these features can be improved!\n\n"+
489+
"You can report an issue at: https://github.com/hashicorp/terraform/issues\n\n"+
490+
"%s\n\n"+
491+
"This is not an error. Your terraform operation completed successfully\n"+
492+
"and your real infrastructure is unaffected by this message.",
493+
err,
494+
)))
495+
496+
return true
497+
}
498+
463499
// contextOpts are the options used to load a context from a command.
464500
type contextOpts struct {
465501
// Path to the directory where the root module is.

‎command/plan.go‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88

9+
"github.com/hashicorp/go-multierror"
910
"github.com/hashicorp/terraform/terraform"
1011
)
1112

@@ -57,6 +58,9 @@ func (c *PlanCommand) Run(args []string) int {
5758
countHook := new(CountHook)
5859
c.Meta.extraHooks = []terraform.Hook{countHook}
5960

61+
// This is going to keep track of shadow errors
62+
var shadowErr error
63+
6064
ctx, _, err := c.Context(contextOpts{
6165
Destroy: destroy,
6266
Path: path,
@@ -73,6 +77,12 @@ func (c *PlanCommand) Run(args []string) int {
7377
return 1
7478
}
7579

80+
// Record any shadow errors for later
81+
if err := ctx.ShadowError(); err != nil {
82+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
83+
err, "input operation:"))
84+
}
85+
7686
if !validateContext(ctx, c.Ui) {
7787
return 1
7888
}
@@ -138,6 +148,15 @@ func (c *PlanCommand) Run(args []string) int {
138148
countHook.ToChange,
139149
countHook.ToRemove+countHook.ToRemoveAndAdd)))
140150

151+
// Record any shadow errors for later
152+
if err := ctx.ShadowError(); err != nil {
153+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
154+
err, "plan operation:"))
155+
}
156+
157+
// If we have an error in the shadow graph, let the user know.
158+
c.outputShadowError(shadowErr, true)
159+
141160
if detailed {
142161
return 2
143162
}

‎command/refresh.go‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88

9+
"github.com/hashicorp/go-multierror"
910
"github.com/hashicorp/terraform/terraform"
1011
)
1112

@@ -79,6 +80,9 @@ func (c *RefreshCommand) Run(args []string) int {
7980
}
8081
}
8182

83+
// This is going to keep track of shadow errors
84+
var shadowErr error
85+
8286
// Build the context based on the arguments given
8387
ctx, _, err := c.Context(contextOpts{
8488
Path: configPath,
@@ -95,6 +99,12 @@ func (c *RefreshCommand) Run(args []string) int {
9599
return 1
96100
}
97101

102+
// Record any shadow errors for later
103+
if err := ctx.ShadowError(); err != nil {
104+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
105+
err, "input operation:"))
106+
}
107+
98108
if !validateContext(ctx, c.Ui) {
99109
return 1
100110
}
@@ -115,6 +125,15 @@ func (c *RefreshCommand) Run(args []string) int {
115125
c.Ui.Output(c.Colorize().Color(outputs))
116126
}
117127

128+
// Record any shadow errors for later
129+
if err := ctx.ShadowError(); err != nil {
130+
shadowErr = multierror.Append(shadowErr, multierror.Prefix(
131+
err, "refresh operation:"))
132+
}
133+
134+
// If we have an error in the shadow graph, let the user know.
135+
c.outputShadowError(shadowErr, true)
136+
118137
return 0
119138
}
120139

0 commit comments

Comments
 (0)