kubernetes binary download: retry downloads for every error during download (after preparing the destination tempfile) (#290)

kubernetes binary download: retry downloads for every error during download (after preparing the destination tempfile)

Signed-off-by: Malte Poll <mp@edgeless.systems>
Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
This commit is contained in:
Malte Poll 2022-07-22 11:10:39 +02:00 committed by GitHub
parent c743398a23
commit ebf76ae7e3

View File

@ -11,7 +11,6 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"syscall"
"time" "time"
"github.com/edgelesssys/constellation/internal/retry" "github.com/edgelesssys/constellation/internal/retry"
@ -41,7 +40,7 @@ func newOSInstaller() *osInstaller {
fs: &afero.Afero{Fs: afero.NewOsFs()}, fs: &afero.Afero{Fs: afero.NewOsFs()},
hClient: &http.Client{}, hClient: &http.Client{},
clock: clock.RealClock{}, clock: clock.RealClock{},
retriable: connectionResetErr, retriable: isRetriable,
} }
} }
@ -152,7 +151,7 @@ func (i *osInstaller) retryDownloadToTempDir(ctx context.Context, url string, tr
downloader: i, downloader: i,
} }
// Retries are cancled as soon as the context is canceled. // Retries are canceled as soon as the context is canceled.
// We need to call NewIntervalRetrier with a clock argument so that the tests can fake the clock by changing the osInstaller clock. // We need to call NewIntervalRetrier with a clock argument so that the tests can fake the clock by changing the osInstaller clock.
retrier := retry.NewIntervalRetrier(&doer, downloadInterval, i.retriable, i.clock) retrier := retry.NewIntervalRetrier(&doer, downloadInterval, i.retriable, i.clock)
if err := retrier.Do(ctx); err != nil { if err := retrier.Do(ctx); err != nil {
@ -172,6 +171,7 @@ func (i *osInstaller) downloadToTempDir(ctx context.Context, url string, transfo
defer func() { defer func() {
if retErr != nil { if retErr != nil {
_ = i.fs.Remove(fileName) _ = i.fs.Remove(fileName)
retErr = &retriableError{err: retErr} // mark any error after this point as retriable
} }
}() }()
defer out.Close() defer out.Close()
@ -242,8 +242,19 @@ func (d *downloadDoer) Do(ctx context.Context) error {
return err return err
} }
func connectionResetErr(err error) bool { // retriableError is an error that can be retried.
return errors.Is(err, syscall.ECONNRESET) type retriableError struct{ err error }
func (e *retriableError) Error() string {
return fmt.Sprintf("retriable error: %s", e.err.Error())
}
func (e *retriableError) Unwrap() error { return e.err }
// isRetriable returns true if the action resulting in this error can be retried.
func isRetriable(err error) bool {
retriableError := &retriableError{}
return errors.As(err, &retriableError)
} }
// verifyTarPath checks if a tar path is valid (must not contain ".." as path element). // verifyTarPath checks if a tar path is valid (must not contain ".." as path element).