Skip to content

Commit f5bd00b

Browse files
Fix the issue of infinite loop caused by connection failure
Signed-off-by: whitewindmills <[email protected]>
1 parent f5ee2ce commit f5bd00b

File tree

2 files changed

+20
-28
lines changed

2 files changed

+20
-28
lines changed

pkg/webhook/interpreter/http.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,17 @@ func (wh *Webhook) writeResponse(w io.Writer, response Response) {
9797
// writeResourceInterpreterResponse writes ar to w.
9898
func (wh *Webhook) writeResourceInterpreterResponse(w io.Writer, interpreterContext configv1alpha1.ResourceInterpreterContext) {
9999
if err := json.NewEncoder(w).Encode(interpreterContext); err != nil {
100-
klog.Errorf("unable to encode the response: %v", err)
101-
wh.writeResponse(w, Errored(http.StatusInternalServerError, err))
100+
klog.Errorf("unable to encode and write the response: %v", err)
101+
// Since the `ar configv1alpha1.ResourceInterpreterContext` is a clear and legal object,
102+
// it should not have problem to be marshalled into bytes.
103+
// The error here is probably caused by the abnormal HTTP connection,
104+
// e.g., broken pipe, so we can only write the error response once,
105+
// to avoid endless circular calling.
106+
// More info: https://github.com/kubernetes-sigs/controller-runtime/pull/1930
107+
serverError := Errored(http.StatusInternalServerError, err)
108+
if err = json.NewEncoder(w).Encode(configv1alpha1.ResourceInterpreterContext{Response: &serverError.ResourceInterpreterResponse}); err != nil {
109+
klog.Errorf("still unable to encode and write the InternalServerError response: %v", err)
110+
}
102111
} else {
103112
response := interpreterContext.Response
104113
if response.Successful {

pkg/webhook/interpreter/http_test.go

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,13 @@ func (m *mockBody) Close() error {
5959
return nil
6060
}
6161

62-
// limitedBadResponseWriter is a custom io.Writer implementation that simulates
63-
// write errors for a specified number of attempts. After a certain number of failures,
64-
// it allows the write operation to succeed.
65-
type limitedBadResponseWriter struct {
66-
failCount int
67-
maxFailures int
62+
// brokenWriter implements the io.Writer interface.
63+
type brokenWriter struct {
64+
http.ResponseWriter
6865
}
6966

70-
// Write simulates writing data to the writer. It forces an error response for
71-
// a limited number of attempts, specified by maxFailures. Once failCount reaches
72-
// maxFailures, it allows the write to succeed.
73-
func (b *limitedBadResponseWriter) Write(p []byte) (n int, err error) {
74-
if b.failCount < b.maxFailures {
75-
b.failCount++
76-
return 0, errors.New("forced write error")
77-
}
78-
// After reaching maxFailures, allow the write to succeed to stop the infinite loop.
79-
return len(p), nil
67+
func (bw *brokenWriter) Write(_ []byte) (int, error) {
68+
return 0, fmt.Errorf("mock: write: broken pipe")
8069
}
8170

8271
func TestServeHTTP(t *testing.T) {
@@ -294,20 +283,14 @@ func TestWriteResourceInterpreterResponse(t *testing.T) {
294283
},
295284
},
296285
{
297-
name: "WriteResourceInterpreterResponse_FailedToWrite_WriterReachedMaxFailures",
286+
name: "should never run into circular calling if the writer has broken",
298287
mockHandler: &HTTPMockHandler{},
299288
res: configv1alpha1.ResourceInterpreterContext{
300289
Response: &configv1alpha1.ResourceInterpreterResponse{},
301290
},
302-
rec: &limitedBadResponseWriter{maxFailures: 3},
303-
verify: func(writer io.Writer, _ *configv1alpha1.ResourceInterpreterResponse) error {
304-
data, ok := writer.(*limitedBadResponseWriter)
305-
if !ok {
306-
return fmt.Errorf("expected writer of type limitedBadResponseWriter but got %T", writer)
307-
}
308-
if data.failCount != data.maxFailures {
309-
return fmt.Errorf("expected %d write failures, got %d", data.maxFailures, data.failCount)
310-
}
291+
rec: &brokenWriter{},
292+
verify: func(_ io.Writer, _ *configv1alpha1.ResourceInterpreterResponse) error {
293+
// reaching here means not running into circular calling
311294
return nil
312295
},
313296
},

0 commit comments

Comments
 (0)