Skip to content

Commit b810d3d

Browse files
add context to action error messages
We want to be informative about how to remidy the issues actions ran into.
1 parent 17e7338 commit b810d3d

File tree

3 files changed

+300
-38
lines changed

3 files changed

+300
-38
lines changed

internal/terraform/context_apply_action_test.go

Lines changed: 183 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ func TestContext2Apply_actions(t *testing.T) {
2323
module map[string]string
2424
mode plans.Mode
2525
prevRunState *states.State
26-
events []providers.InvokeActionEvent
26+
events func(req providers.InvokeActionRequest) []providers.InvokeActionEvent
2727
callingInvokeReturnsDiagnostics func(providers.InvokeActionRequest) tfdiags.Diagnostics
28-
planOpts *PlanOpts
28+
29+
planOpts *PlanOpts
2930

3031
expectInvokeActionCalled bool
3132
expectInvokeActionCalls []providers.InvokeActionRequest
@@ -160,23 +161,79 @@ resource "test_object" "a" {
160161
`,
161162
},
162163
expectInvokeActionCalled: true,
163-
events: []providers.InvokeActionEvent{
164-
providers.InvokeActionEvent_Completed{
165-
Diagnostics: tfdiags.Diagnostics{
166-
tfdiags.Sourceless(
167-
tfdiags.Error,
168-
"test case for failing",
169-
"this simulates a provider failing",
170-
),
164+
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
165+
return []providers.InvokeActionEvent{
166+
providers.InvokeActionEvent_Completed{
167+
Diagnostics: tfdiags.Diagnostics{
168+
tfdiags.Sourceless(
169+
tfdiags.Error,
170+
"test case for failing",
171+
"this simulates a provider failing",
172+
),
173+
},
171174
},
172-
},
175+
}
173176
},
174177

175178
expectDiagnostics: tfdiags.Diagnostics{
176179
tfdiags.Sourceless(
177180
tfdiags.Error,
178-
"test case for failing",
179-
"this simulates a provider failing",
181+
"Failed to apply actions before test_object.a",
182+
"An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing\n",
183+
),
184+
},
185+
},
186+
187+
"before_create failing with successfully completed actions": {
188+
module: map[string]string{
189+
"main.tf": `
190+
action "act_unlinked" "hello" {}
191+
action "act_unlinked" "world" {}
192+
action "act_unlinked" "failure" {
193+
config {
194+
attr = "failure"
195+
}
196+
}
197+
resource "test_object" "a" {
198+
lifecycle {
199+
action_trigger {
200+
events = [before_create]
201+
actions = [action.act_unlinked.hello, action.act_unlinked.world, action.act_unlinked.failure]
202+
}
203+
}
204+
}
205+
`,
206+
},
207+
expectInvokeActionCalled: true,
208+
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
209+
if !req.PlannedActionData.IsNull() && req.PlannedActionData.GetAttr("attr").AsString() == "failure" {
210+
return []providers.InvokeActionEvent{
211+
providers.InvokeActionEvent_Completed{
212+
Diagnostics: tfdiags.Diagnostics{
213+
tfdiags.Sourceless(
214+
tfdiags.Error,
215+
"test case for failing",
216+
"this simulates a provider failing",
217+
),
218+
},
219+
},
220+
}
221+
} else {
222+
return []providers.InvokeActionEvent{
223+
providers.InvokeActionEvent_Completed{},
224+
}
225+
}
226+
},
227+
228+
expectDiagnostics: tfdiags.Diagnostics{
229+
tfdiags.Sourceless(
230+
tfdiags.Error,
231+
"Failed to apply actions before test_object.a",
232+
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
233+
The following actions were successfully invoked:
234+
- action.act_unlinked.hello
235+
- action.act_unlinked.world
236+
As the resource did not change, these actions will be re-invoked in the next apply.`,
180237
),
181238
},
182239
},
@@ -208,8 +265,104 @@ resource "test_object" "a" {
208265
expectDiagnostics: tfdiags.Diagnostics{
209266
tfdiags.Sourceless(
210267
tfdiags.Error,
211-
"test case for failing",
212-
"this simulates a provider failing before the action is invoked",
268+
"Failed to apply actions before test_object.a",
269+
"An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing before the action is invoked\n",
270+
),
271+
},
272+
},
273+
274+
"after_create failing": {
275+
module: map[string]string{
276+
"main.tf": `
277+
action "act_unlinked" "hello" {}
278+
resource "test_object" "a" {
279+
lifecycle {
280+
action_trigger {
281+
events = [after_create]
282+
actions = [action.act_unlinked.hello]
283+
}
284+
}
285+
}
286+
`,
287+
},
288+
expectInvokeActionCalled: true,
289+
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
290+
return []providers.InvokeActionEvent{
291+
providers.InvokeActionEvent_Completed{
292+
Diagnostics: tfdiags.Diagnostics{
293+
tfdiags.Sourceless(
294+
tfdiags.Error,
295+
"test case for failing",
296+
"this simulates a provider failing",
297+
),
298+
},
299+
},
300+
}
301+
},
302+
303+
expectDiagnostics: tfdiags.Diagnostics{
304+
tfdiags.Sourceless(
305+
tfdiags.Error,
306+
"Failed to apply actions after test_object.a",
307+
`An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing
308+
309+
The following actions were not yet invoked:
310+
- action.act_unlinked.hello
311+
These actions will not be triggered in the next apply, please run "terraform invoke" to invoke them.`,
312+
),
313+
},
314+
},
315+
316+
"after_create failing with successfully completed actions": {
317+
module: map[string]string{
318+
"main.tf": `
319+
action "act_unlinked" "hello" {}
320+
action "act_unlinked" "world" {}
321+
action "act_unlinked" "failure" {
322+
config {
323+
attr = "failure"
324+
}
325+
}
326+
resource "test_object" "a" {
327+
lifecycle {
328+
action_trigger {
329+
events = [after_create]
330+
actions = [action.act_unlinked.hello, action.act_unlinked.world, action.act_unlinked.failure]
331+
}
332+
}
333+
}
334+
`,
335+
},
336+
expectInvokeActionCalled: true,
337+
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
338+
if !req.PlannedActionData.IsNull() && req.PlannedActionData.GetAttr("attr").AsString() == "failure" {
339+
return []providers.InvokeActionEvent{
340+
providers.InvokeActionEvent_Completed{
341+
Diagnostics: tfdiags.Diagnostics{
342+
tfdiags.Sourceless(
343+
tfdiags.Error,
344+
"test case for failing",
345+
"this simulates a provider failing",
346+
),
347+
},
348+
},
349+
}
350+
} else {
351+
return []providers.InvokeActionEvent{
352+
providers.InvokeActionEvent_Completed{},
353+
}
354+
}
355+
},
356+
357+
expectDiagnostics: tfdiags.Diagnostics{
358+
tfdiags.Sourceless(
359+
tfdiags.Error,
360+
"Failed to apply actions after test_object.a",
361+
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
362+
363+
The following actions were not yet invoked:
364+
- action.act_unlinked.failure
365+
These actions will not be triggered in the next apply, please run "terraform invoke" to invoke them.`,
213366
),
214367
},
215368
},
@@ -242,7 +395,7 @@ resource "test_object" "a" {
242395
tfdiags.Sourceless(
243396
tfdiags.Error,
244397
"test case for failing",
245-
"this simulates a provider failing before the action is invoked",
398+
"this simulates a provider failing",
246399
),
247400
}
248401
}
@@ -251,10 +404,14 @@ resource "test_object" "a" {
251404
expectDiagnostics: tfdiags.Diagnostics{
252405
tfdiags.Sourceless(
253406
tfdiags.Error,
254-
"test case for failing",
255-
"this simulates a provider failing before the action is invoked",
407+
"Failed to apply actions before test_object.a",
408+
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
409+
The following actions were successfully invoked:
410+
- action.act_unlinked.hello
411+
As the resource did not change, these actions will be re-invoked in the next apply.`,
256412
),
257413
},
414+
258415
// We expect two calls but not the third one, because the second action fails
259416
expectInvokeActionCalls: []providers.InvokeActionRequest{{
260417
ActionType: "act_unlinked",
@@ -305,7 +462,7 @@ resource "test_object" "a" {
305462
tfdiags.Sourceless(
306463
tfdiags.Error,
307464
"test case for failing",
308-
"this simulates a provider failing before the action is invoked",
465+
"this simulates a provider failing",
309466
),
310467
}
311468
}
@@ -314,8 +471,11 @@ resource "test_object" "a" {
314471
expectDiagnostics: tfdiags.Diagnostics{
315472
tfdiags.Sourceless(
316473
tfdiags.Error,
317-
"test case for failing",
318-
"this simulates a provider failing before the action is invoked",
474+
"Failed to apply actions before test_object.a",
475+
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
476+
The following actions were successfully invoked:
477+
- action.act_unlinked.hello
478+
As the resource did not change, these actions will be re-invoked in the next apply.`,
319479
),
320480
},
321481
// We expect two calls but not the third one, because the second action fails
@@ -524,8 +684,8 @@ resource "test_object" "a" {
524684
defaultEvents = append(defaultEvents, providers.InvokeActionEvent_Completed{})
525685

526686
events := defaultEvents
527-
if len(tc.events) > 0 {
528-
events = tc.events
687+
if tc.events != nil {
688+
events = tc.events(req)
529689
}
530690

531691
return providers.InvokeActionResponse{
@@ -571,7 +731,6 @@ resource "test_object" "a" {
571731
},
572732
},
573733
},
574-
575734
Unlinked: &providers.UnlinkedAction{},
576735
},
577736
},

0 commit comments

Comments
 (0)