@@ -455,6 +455,7 @@ type v2repository struct {
455
455
name string
456
456
endpoint url.URL
457
457
token string
458
+ retries int
458
459
}
459
460
460
461
// v2tags describes the tags/list returned by the Docker V2 registry.
@@ -482,6 +483,13 @@ func (repo *v2repository) getTags(c *connection) (map[string]string, error) {
482
483
switch code := resp .StatusCode ; {
483
484
case code == http .StatusUnauthorized :
484
485
if len (repo .token ) != 0 {
486
+ // The DockerHub returns JWT tokens that take effect at "now" at second resolution, which means clients can
487
+ // be rejected when requests are made near the time boundary.
488
+ if repo .retries > 0 {
489
+ repo .retries --
490
+ time .Sleep (time .Second / 2 )
491
+ return repo .getTags (c )
492
+ }
485
493
delete (c .cached , repo .name )
486
494
// docker will not return a NotFound on any repository URL - for backwards compatibilty, return NotFound on the
487
495
// repo
@@ -491,6 +499,7 @@ func (repo *v2repository) getTags(c *connection) (map[string]string, error) {
491
499
if err != nil {
492
500
return nil , fmt .Errorf ("error getting image tags for %s: %v" , repo .name , err )
493
501
}
502
+ repo .retries = 2
494
503
repo .token = token
495
504
return repo .getTags (c )
496
505
@@ -532,6 +541,13 @@ func (repo *v2repository) getTaggedImage(c *connection, tag, userTag string) (*I
532
541
switch code := resp .StatusCode ; {
533
542
case code == http .StatusUnauthorized :
534
543
if len (repo .token ) != 0 {
544
+ // The DockerHub returns JWT tokens that take effect at "now" at second resolution, which means clients can
545
+ // be rejected when requests are made near the time boundary.
546
+ if repo .retries > 0 {
547
+ repo .retries --
548
+ time .Sleep (time .Second / 2 )
549
+ return repo .getTaggedImage (c , tag , userTag )
550
+ }
535
551
delete (c .cached , repo .name )
536
552
// docker will not return a NotFound on any repository URL - for backwards compatibilty, return NotFound on the
537
553
// repo
@@ -543,6 +559,7 @@ func (repo *v2repository) getTaggedImage(c *connection, tag, userTag string) (*I
543
559
if err != nil {
544
560
return nil , fmt .Errorf ("error getting image for %s:%s: %v" , repo .name , tag , err )
545
561
}
562
+ repo .retries = 2
546
563
repo .token = token
547
564
return repo .getTaggedImage (c , tag , userTag )
548
565
case code == http .StatusNotFound :
0 commit comments