...
1
16
17 package cli
18
19 import (
20 "bytes"
21 "encoding/json"
22 "io"
23 "net/http"
24 "strings"
25 )
26
27 type retryingRoundTripper struct {
28 wrapped http.RoundTripper
29 }
30
31 func (rt *retryingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
32 return rt.roundTrip(req, 1, nil)
33 }
34
35 func (rt *retryingRoundTripper) roundTrip(req *http.Request, retry int, prevResp *http.Response) (*http.Response, error) {
36 if retry < 0 {
37 return prevResp, nil
38 }
39 resp, rtErr := rt.wrapped.RoundTrip(req)
40 if rtErr != nil {
41 return resp, rtErr
42 }
43 if resp.StatusCode < 500 {
44 return resp, rtErr
45 }
46 if resp.Header.Get("content-type") != "application/json" {
47 return resp, rtErr
48 }
49 b, err := io.ReadAll(resp.Body)
50 resp.Body.Close()
51 if err != nil {
52 return resp, rtErr
53 }
54
55 var ke kubernetesError
56 r := bytes.NewReader(b)
57 err = json.NewDecoder(r).Decode(&ke)
58 r.Seek(0, io.SeekStart)
59 resp.Body = io.NopCloser(r)
60 if err != nil {
61 return resp, rtErr
62 }
63 if ke.Code < 500 {
64 return resp, rtErr
65 }
66
67 if strings.HasSuffix(ke.Message, "etcdserver: leader changed") {
68 return rt.roundTrip(req, retry-1, resp)
69 }
70
71 if strings.HasSuffix(ke.Message, "raft proposal dropped") {
72 return rt.roundTrip(req, retry-1, resp)
73 }
74 return resp, rtErr
75 }
76
77 type kubernetesError struct {
78 Message string `json:"message"`
79 Code int `json:"code"`
80 }
81
View as plain text