Browse code

c8d/pull: Avoid platforms.Default()

Introduce `hostPlatformSpec` as a replacement, so we can decouple from
containerd platforms logic and override for tests.

Default image-store operations should share the same host platform
preference as pulls, otherwise list, identity cache, and classic-builder
selection can still rank plain linux/amd64 ahead of compatible amd64
variants.

Route those unspecified-platform paths through the ImageService host
matcher so amd64 variant fallback stays consistent.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Paweł Gronowski authored on 2026/06/09 02:56:17
Showing 5 changed files
... ...
@@ -200,7 +200,7 @@ func newROLayerForImage(ctx context.Context, imgDesc *ocispec.Descriptor, i *Ima
200 200
 		return nil, errors.New("can't make an RO layer for a nil image :'(")
201 201
 	}
202 202
 
203
-	platMatcher := platforms.Default()
203
+	platMatcher := i.hostPlatformMatcher()
204 204
 	if platform != nil {
205 205
 		platMatcher = platforms.Only(*platform)
206 206
 	}
... ...
@@ -449,7 +449,7 @@ func (i *ImageService) CreateImage(ctx context.Context, config []byte, parent st
449 449
 		if err != nil {
450 450
 			return nil, err
451 451
 		}
452
-		parentImageManifest, err := c8dimages.Manifest(ctx, i.content, parentDesc, platforms.Default())
452
+		parentImageManifest, err := c8dimages.Manifest(ctx, i.content, parentDesc, i.hostPlatformMatcher())
453 453
 		if err != nil {
454 454
 			return nil, err
455 455
 		}
... ...
@@ -424,7 +424,7 @@ func (i *ImageService) refreshImageIdentityCacheKey(ctx context.Context, cacheKe
424 424
 		return nil
425 425
 	}
426 426
 
427
-	platformMatcher, err := imageIdentityPlatformMatcher(bestPlatform)
427
+	platformMatcher, err := i.imageIdentityPlatformMatcher(bestPlatform)
428 428
 	if err != nil {
429 429
 		return err
430 430
 	}
... ...
@@ -448,9 +448,9 @@ func (i *ImageService) refreshImageIdentityCacheKey(ctx context.Context, cacheKe
448 448
 	return nil
449 449
 }
450 450
 
451
-func imageIdentityPlatformMatcher(platform string) (platforms.MatchComparer, error) {
451
+func (i *ImageService) imageIdentityPlatformMatcher(platform string) (platforms.MatchComparer, error) {
452 452
 	if platform == "" {
453
-		return matchAnyWithPreference(platforms.Default(), nil), nil
453
+		return matchAnyWithPreference(i.hostPlatformMatcher(), nil), nil
454 454
 	}
455 455
 	parsed, err := platforms.Parse(platform)
456 456
 	if err != nil {
... ...
@@ -541,7 +541,7 @@ func (i *ImageService) warmImageIdentityCache(ctx context.Context, img c8dimages
541 541
 	go func() {
542 542
 		warmCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), imageIdentityWarmupTimeout)
543 543
 		defer cancel()
544
-		multi, err := i.multiPlatformSummary(warmCtx, img, matchAnyWithPreference(platforms.Default(), nil))
544
+		multi, err := i.multiPlatformSummary(warmCtx, img, matchAnyWithPreference(i.hostPlatformMatcher(), nil))
545 545
 		if err != nil {
546 546
 			log.G(warmCtx).WithError(err).WithField("image", img.Name).Debug("failed to build image identity cache in background")
547 547
 			return
... ...
@@ -107,7 +107,7 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
107 107
 	}
108 108
 
109 109
 	// TODO: Allow platform override?
110
-	platformMatcher := matchAnyWithPreference(platforms.Default(), nil)
110
+	platformMatcher := matchAnyWithPreference(i.hostPlatformMatcher(), nil)
111 111
 
112 112
 	for _, img := range imgs {
113 113
 		isDangling := isDanglingImage(img)
... ...
@@ -138,7 +138,7 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
138 138
 		}()
139 139
 	}
140 140
 
141
-	p := platforms.Default()
141
+	p := i.hostPlatformMatcher()
142 142
 	if platform != nil {
143 143
 		p = platforms.Only(*platform)
144 144
 	}
... ...
@@ -252,7 +252,7 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
252 252
 			// the same message as the graphdrivers backend.
253 253
 			// The one returned by containerd doesn't contain the platform and is much less informative.
254 254
 			if strings.Contains(err.Error(), "platform") {
255
-				platformStr := platforms.DefaultString()
255
+				platformStr := platforms.FormatAll(i.hostPlatformSpec())
256 256
 				if platform != nil {
257 257
 					platformStr = platforms.FormatAll(*platform)
258 258
 				}
... ...
@@ -65,9 +65,14 @@ func (i *ImageService) matchRequestedOrDefault(
65 65
 
66 66
 // hostPlatformMatcher returns a platform match comparer that matches the host platform.
67 67
 func (i *ImageService) hostPlatformMatcher() platforms.MatchComparer {
68
-	// Allow to override the host platform for testing purposes.
68
+	return platforms.Only(i.hostPlatformSpec())
69
+}
70
+
71
+// hostPlatformSpec returns the host platform specification.
72
+func (i *ImageService) hostPlatformSpec() ocispec.Platform {
73
+	// Allow tests to override the host platform before constructing matchers.
69 74
 	if i.defaultPlatformOverride != nil {
70
-		return platforms.Only(*i.defaultPlatformOverride)
75
+		return *i.defaultPlatformOverride
71 76
 	}
72
-	return platforms.Default()
77
+	return platforms.DefaultSpec()
73 78
 }