mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-23 19:57:02 +00:00
fix: retry on download errors
to avoid failing because of issues like connection reset
This commit is contained in:
parent
347cd5e4c9
commit
7b9163b6c9
2 changed files with 67 additions and 13 deletions
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -74,6 +75,24 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := r.c.Get(url)
|
resp, err := r.c.Get(url)
|
||||||
|
// retry on transient errors, ie. connection reset by peer
|
||||||
|
if err != nil {
|
||||||
|
if opErr, ok := err.(*net.OpError); ok {
|
||||||
|
if r.debug {
|
||||||
|
log.Printf("failed downloading schema at %s due to network error, retrying: %s", url, opErr)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
resp, err = r.c.Get(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// retry on server errors
|
||||||
|
if resp != nil && resp.StatusCode >= 500 {
|
||||||
|
if r.debug {
|
||||||
|
log.Printf("failed downloading schema at %s due to server error, retrying: %d", url, resp.StatusCode)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
resp, err = r.c.Get(url)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failed downloading schema at %s: %s", url, err)
|
msg := fmt.Sprintf("failed downloading schema at %s: %s", url, err)
|
||||||
if r.debug {
|
if r.debug {
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,29 @@ package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockHTTPGetter struct {
|
type mockHTTPGetter struct {
|
||||||
httpGet func(string) (*http.Response, error)
|
callNumber int
|
||||||
|
httpGet func(mockHTTPGetter, string) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockHTTPGetter(f func(string) (*http.Response, error)) *mockHTTPGetter {
|
func newMockHTTPGetter(f func(mockHTTPGetter, string) (*http.Response, error)) *mockHTTPGetter {
|
||||||
return &mockHTTPGetter{
|
return &mockHTTPGetter{
|
||||||
httpGet: f,
|
callNumber: 0,
|
||||||
|
httpGet: f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (m mockHTTPGetter) Get(url string) (resp *http.Response, err error) {
|
func (m *mockHTTPGetter) Get(url string) (resp *http.Response, err error) {
|
||||||
return m.httpGet(url)
|
m.callNumber = m.callNumber + 1
|
||||||
|
return m.httpGet(*m, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDownloadSchema(t *testing.T) {
|
func TestDownloadSchema(t *testing.T) {
|
||||||
|
|
@ -33,21 +38,28 @@ func TestDownloadSchema(t *testing.T) {
|
||||||
expectErr error
|
expectErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"error when downloading",
|
"retry connection reset by peer",
|
||||||
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
|
newMockHTTPGetter(func(c mockHTTPGetter, url string) (resp *http.Response, err error) {
|
||||||
return nil, fmt.Errorf("failed downloading from registry")
|
if c.callNumber == 1 {
|
||||||
|
return nil, &net.OpError{Err: errors.New("connection reset by peer")}
|
||||||
|
} else {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
"http://kubernetesjson.dev",
|
"http://kubernetesjson.dev",
|
||||||
true,
|
true,
|
||||||
"Deployment",
|
"Deployment",
|
||||||
"v1",
|
"v1",
|
||||||
"1.18.0",
|
"1.18.0",
|
||||||
|
[]byte("http response mock body"),
|
||||||
nil,
|
nil,
|
||||||
fmt.Errorf("failed downloading schema at http://kubernetesjson.dev: failed downloading from registry"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"getting 404",
|
"getting 404",
|
||||||
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
|
newMockHTTPGetter(func(c mockHTTPGetter, url string) (resp *http.Response, err error) {
|
||||||
return &http.Response{
|
return &http.Response{
|
||||||
StatusCode: http.StatusNotFound,
|
StatusCode: http.StatusNotFound,
|
||||||
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
||||||
|
|
@ -62,8 +74,8 @@ func TestDownloadSchema(t *testing.T) {
|
||||||
fmt.Errorf("could not find schema at http://kubernetesjson.dev"),
|
fmt.Errorf("could not find schema at http://kubernetesjson.dev"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"getting 503",
|
"getting 500",
|
||||||
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
|
newMockHTTPGetter(func(c mockHTTPGetter, url string) (resp *http.Response, err error) {
|
||||||
return &http.Response{
|
return &http.Response{
|
||||||
StatusCode: http.StatusServiceUnavailable,
|
StatusCode: http.StatusServiceUnavailable,
|
||||||
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
||||||
|
|
@ -77,9 +89,32 @@ func TestDownloadSchema(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
fmt.Errorf("error while downloading schema at http://kubernetesjson.dev - received HTTP status 503"),
|
fmt.Errorf("error while downloading schema at http://kubernetesjson.dev - received HTTP status 503"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"retry 503",
|
||||||
|
newMockHTTPGetter(func(c mockHTTPGetter, url string) (resp *http.Response, err error) {
|
||||||
|
if c.callNumber == 1 {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: http.StatusServiceUnavailable,
|
||||||
|
Body: io.NopCloser(strings.NewReader("503 http response mock body")),
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"http://kubernetesjson.dev",
|
||||||
|
true,
|
||||||
|
"Deployment",
|
||||||
|
"v1",
|
||||||
|
"1.18.0",
|
||||||
|
[]byte("http response mock body"),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"200",
|
"200",
|
||||||
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
|
newMockHTTPGetter(func(c mockHTTPGetter, url string) (resp *http.Response, err error) {
|
||||||
return &http.Response{
|
return &http.Response{
|
||||||
StatusCode: http.StatusOK,
|
StatusCode: http.StatusOK,
|
||||||
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
Body: io.NopCloser(strings.NewReader("http response mock body")),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue