Skip to content

Commit fec1e14

Browse files
aidansteelebmoffatt
authored andcommitted
CloudFormation wrapper panics are reported as failures (closes #172) (#174)
Panics are not recovered, as this would cause the stacktrace to be lost by handlers higher in the stack that are yet to be unwound.
1 parent ec2fec7 commit fec1e14

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

cfn/wrap.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,19 @@ type CustomResourceFunction func(context.Context, Event) (physicalResourceID str
2121
func lambdaWrapWithClient(lambdaFunction CustomResourceFunction, client httpClient) (fn CustomResourceLambdaFunction) {
2222
fn = func(ctx context.Context, event Event) (reason string, err error) {
2323
r := NewResponse(&event)
24+
25+
funcDidPanic := true
26+
defer func() {
27+
if funcDidPanic {
28+
r.Status = StatusFailed
29+
r.Reason = "Function panicked, see log stream for details"
30+
r.sendWith(client)
31+
}
32+
}()
33+
2434
r.PhysicalResourceID, r.Data, err = lambdaFunction(ctx, event)
35+
funcDidPanic = false
36+
2537
if r.PhysicalResourceID == "" {
2638
log.Println("PhysicalResourceID must exist, copying Log Stream name")
2739
r.PhysicalResourceID = lambdacontext.LogStreamName

cfn/wrap_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,34 @@ func TestCopyLambdaLogStream(t *testing.T) {
5050
lambdacontext.LogStreamName = lgs
5151
}
5252

53+
func TestPanicSendsFailure(t *testing.T) {
54+
didSendStatus := false
55+
56+
client := &mockClient{
57+
DoFunc: func(req *http.Request) (*http.Response, error) {
58+
response := extractResponseBody(t, req)
59+
assert.Equal(t, StatusFailed, response.Status)
60+
didSendStatus = response.Status == StatusFailed
61+
62+
return &http.Response{
63+
StatusCode: http.StatusOK,
64+
Body: nopCloser{bytes.NewBufferString("")},
65+
}, nil
66+
},
67+
}
68+
69+
fn := func(ctx context.Context, event Event) (physicalResourceID string, data map[string]interface{}, err error) {
70+
err = errors.New("some panic that shouldn't be caught")
71+
panic(err)
72+
}
73+
74+
assert.Panics(t, func() {
75+
lambdaWrapWithClient(fn, client)(context.TODO(), *testEvent)
76+
})
77+
78+
assert.True(t, didSendStatus, "FAILED should be sent to CloudFormation service")
79+
}
80+
5381
func TestDontCopyLogicalResourceId(t *testing.T) {
5482
client := &mockClient{
5583
DoFunc: func(req *http.Request) (*http.Response, error) {

0 commit comments

Comments
 (0)