@@ -212,11 +212,7 @@ func UploadCachedImage(imgName string) error {
212212 return err
213213 }
214214 if err := uploadImage (tag , imagePathInCache (imgName )); err != nil {
215- // this time try determine image tags from tarball
216-
217- manifest , err := tarball .LoadManifest (func () (io.ReadCloser , error ) {
218- return os .Open (imagePathInCache (imgName ))
219- })
215+ manifest , err := loadManifestWithRetry (imagePathInCache (imgName ))
220216 if err != nil || len (manifest ) == 0 || len (manifest [0 ].RepoTags ) == 0 {
221217 return fmt .Errorf ("failed to determine the image tag from tarball, err: %v" , err )
222218 }
@@ -239,9 +235,9 @@ func uploadImage(tag name.Tag, p string) error {
239235 return fmt .Errorf ("neither daemon nor remote" )
240236 }
241237
242- img , err = tarball . ImageFromPath (p , & tag )
238+ img , err = imageFromPathWithRetry (p , tag )
243239 if err != nil {
244- return errors . Wrap ( err , "tarball" )
240+ return err
245241 }
246242 ref := name .Reference (tag )
247243
@@ -271,6 +267,52 @@ func uploadRemote(ref name.Reference, img v1.Image, p v1.Platform) error {
271267 return err
272268}
273269
270+ func imageFromPathWithRetry (path string , tag name.Tag ) (v1.Image , error ) {
271+ var lastErr error
272+ const maxAttempts = 3
273+ for i := 0 ; i < maxAttempts ; i ++ {
274+ if i > 0 {
275+ time .Sleep (200 * time .Millisecond )
276+ }
277+ img , err := tarball .ImageFromPath (path , & tag )
278+ if err == nil {
279+ return img , nil
280+ }
281+ lastErr = errors .Wrap (err , "tarball" )
282+ if ! isRetryableEOF (err ) {
283+ return nil , lastErr
284+ }
285+ klog .Infof ("retrying tarball read for %s due to EOF (%d/%d)" , path , i + 1 , maxAttempts )
286+ }
287+ return nil , lastErr
288+ }
289+
290+ func loadManifestWithRetry (path string ) (tarball.Manifest , error ) {
291+ var lastErr error
292+ const maxAttempts = 3
293+ for i := 0 ; i < maxAttempts ; i ++ {
294+ if i > 0 {
295+ time .Sleep (200 * time .Millisecond )
296+ }
297+ manifest , err := tarball .LoadManifest (func () (io.ReadCloser , error ) {
298+ return os .Open (path )
299+ })
300+ if err == nil {
301+ return manifest , nil
302+ }
303+ lastErr = err
304+ if ! isRetryableEOF (err ) {
305+ return nil , lastErr
306+ }
307+ klog .Infof ("retrying manifest read for %s due to EOF (%d/%d)" , path , i + 1 , maxAttempts )
308+ }
309+ return nil , lastErr
310+ }
311+
312+ func isRetryableEOF (err error ) bool {
313+ return errors .Is (err , io .ErrUnexpectedEOF ) || errors .Is (err , io .EOF ) || strings .Contains (err .Error (), "unexpected EOF" )
314+ }
315+
274316// See https://github.com/kubernetes/minikube/issues/10402
275317// check if downloaded image Architecture field matches the requested and fix it otherwise
276318func fixPlatform (ref name.Reference , img v1.Image , p v1.Platform ) (v1.Image , error ) {
0 commit comments