From 6953340b14a016705ec5fa80da3cabbe21f3778e Mon Sep 17 00:00:00 2001 From: Flavian Missi Date: Tue, 9 Sep 2025 09:44:52 +0200 Subject: [PATCH 1/2] pkg/image: conditionally parse raw image manifest the Image REST strategy logs errors when it cannot parse the raw json manifest when creating an Image object. however, this is not an error, as a call to this api might have already cleared the DockerImageManifest from the Image object. --- .../apiserver/registry/image/strategy.go | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/pkg/image/apiserver/registry/image/strategy.go b/pkg/image/apiserver/registry/image/strategy.go index 844831ea1..ad473b07f 100644 --- a/pkg/image/apiserver/registry/image/strategy.go +++ b/pkg/image/apiserver/registry/image/strategy.go @@ -52,28 +52,40 @@ func (s imageStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) utilruntime.HandleError(fmt.Errorf("unable to update image metadata for %q: %v", newImage.Name, err)) } - manifest, _, err := distribution.UnmarshalManifest( - newImage.DockerImageManifestMediaType, - []byte(newImage.DockerImageManifest), - ) - if err != nil { - utilruntime.HandleError(fmt.Errorf("unable to parse manifest for %q: %v", newImage.Name, err)) - } + // initially, the code in this function did not account for these + // different contexts. + // the code in this function is called from two contexts: + // 1. image stream imports, which are also triggered by creating image + // streams and adding tags to them; + // 2. direct pushes to the internal registry, i.e. podman push + // on 1. the raw manifest json is cleared from image.DockerImageManifest + // to avoid unbound growth of Image objects in etcd; and on 2. the raw + // manifest json is still set in the image.DockerImageManifest. + // the code block below should not cause side effects on either path. + if len(newImage.DockerImageManifest) != 0 { + manifest, _, err := distribution.UnmarshalManifest( + newImage.DockerImageManifestMediaType, + []byte(newImage.DockerImageManifest), + ) + if err != nil { + utilruntime.HandleError(fmt.Errorf("unable to parse manifest for %q: %v", newImage.Name, err)) + } - if mlist, ok := manifest.(*manifestlist.DeserializedManifestList); ok { - subManifests := []imageapi.ImageManifest{} - for _, m := range mlist.Manifests { - im := imageapi.ImageManifest{ - Digest: m.Digest.String(), - MediaType: m.MediaType, - ManifestSize: m.Size, - Architecture: m.Platform.Architecture, - OS: m.Platform.OS, - Variant: m.Platform.Variant, + if mlist, ok := manifest.(*manifestlist.DeserializedManifestList); ok { + subManifests := []imageapi.ImageManifest{} + for _, m := range mlist.Manifests { + im := imageapi.ImageManifest{ + Digest: m.Digest.String(), + MediaType: m.MediaType, + ManifestSize: m.Size, + Architecture: m.Platform.Architecture, + OS: m.Platform.OS, + Variant: m.Platform.Variant, + } + subManifests = append(subManifests, im) } - subManifests = append(subManifests, im) + newImage.DockerImageManifests = subManifests } - newImage.DockerImageManifests = subManifests } if newImage.Annotations[imagev1.ImageManifestBlobStoredAnnotation] == "true" { From e5b8672bacb5a5241a93444055f3d16ce8b6d0e3 Mon Sep 17 00:00:00 2001 From: Flavian Missi Date: Tue, 9 Sep 2025 10:57:45 +0200 Subject: [PATCH 2/2] pkg/image: pre-allocate subManifests slice --- pkg/image/apiserver/registry/image/strategy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/image/apiserver/registry/image/strategy.go b/pkg/image/apiserver/registry/image/strategy.go index ad473b07f..d7d37fa6e 100644 --- a/pkg/image/apiserver/registry/image/strategy.go +++ b/pkg/image/apiserver/registry/image/strategy.go @@ -72,7 +72,7 @@ func (s imageStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) } if mlist, ok := manifest.(*manifestlist.DeserializedManifestList); ok { - subManifests := []imageapi.ImageManifest{} + subManifests := make([]imageapi.ImageManifest, 0, len(mlist.Manifests)) for _, m := range mlist.Manifests { im := imageapi.ImageManifest{ Digest: m.Digest.String(),