Skip to content

Commit a43a2e0

Browse files
authored
Merge pull request #4062 from apostasie/qa-fixes
[P0] Fix #3513 (`[MAJOR] content digest not found`)
2 parents 87a9f52 + 751c1eb commit a43a2e0

File tree

7 files changed

+74
-7
lines changed

7 files changed

+74
-7
lines changed

pkg/cmd/builder/build.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
127127
if _, err := imageService.Create(ctx, image); err != nil {
128128
// if already exists; skip.
129129
if errors.Is(err, errdefs.ErrAlreadyExists) {
130-
if err = imageService.Delete(ctx, targetRef); err != nil {
130+
if err = imageService.Delete(ctx, targetRef, images.SynchronousDelete()); err != nil {
131131
return err
132132
}
133133
if _, err = imageService.Create(ctx, image); err != nil {

pkg/cmd/image/convert.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
190190
}
191191

192192
// converter.Convert() gains the lease by itself
193-
newImg, err := converter.Convert(ctx, client, targetRef, srcRef, convertOpts...)
193+
newImg, err := converterutil.Convert(ctx, client, targetRef, srcRef, convertOpts...)
194194
if err != nil {
195195
return err
196196
}
@@ -208,7 +208,7 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
208208
return err
209209
}
210210
is := client.ImageService()
211-
_ = is.Delete(ctx, newI.Name)
211+
_ = is.Delete(ctx, newI.Name, images.SynchronousDelete())
212212
finimg, err := is.Create(ctx, *newI)
213213
if err != nil {
214214
return err

pkg/cmd/image/crypt.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/containerd/imgcrypt/v2/images/encryption/parsehelpers"
3131

3232
"github.com/containerd/nerdctl/v2/pkg/api/types"
33+
nerdconverter "github.com/containerd/nerdctl/v2/pkg/imgutil/converter"
3334
"github.com/containerd/nerdctl/v2/pkg/platformutil"
3435
"github.com/containerd/nerdctl/v2/pkg/referenceutil"
3536
)
@@ -93,7 +94,7 @@ func Crypt(ctx context.Context, client *containerd.Client, srcRawRef, targetRawR
9394
convertOpts = append(convertOpts, converter.WithIndexConvertFunc(convertFunc))
9495

9596
// converter.Convert() gains the lease by itself
96-
newImg, err := converter.Convert(ctx, client, targetRef, srcRef, convertOpts...)
97+
newImg, err := nerdconverter.Convert(ctx, client, targetRef, srcRef, convertOpts...)
9798
if err != nil {
9899
return err
99100
}

pkg/cmd/image/push.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343

4444
"github.com/containerd/nerdctl/v2/pkg/api/types"
4545
"github.com/containerd/nerdctl/v2/pkg/errutil"
46+
nerdconverter "github.com/containerd/nerdctl/v2/pkg/imgutil/converter"
4647
"github.com/containerd/nerdctl/v2/pkg/imgutil/dockerconfigresolver"
4748
"github.com/containerd/nerdctl/v2/pkg/imgutil/push"
4849
"github.com/containerd/nerdctl/v2/pkg/ipfs"
@@ -119,7 +120,12 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
119120
pushRef = ref + "-tmp-reduced-platform"
120121
// Push fails with "400 Bad Request" when the manifest is multi-platform but we do not locally have multi-platform blobs.
121122
// So we create a tmp reduced-platform image to avoid the error.
122-
platImg, err := converter.Convert(ctx, client, pushRef, ref, converter.WithPlatform(platMC))
123+
// Ensure all the layers are here: https://github.com/containerd/nerdctl/issues/3425
124+
err = EnsureAllContent(ctx, client, ref, platMC, options.GOptions)
125+
if err != nil {
126+
return err
127+
}
128+
platImg, err := nerdconverter.Convert(ctx, client, pushRef, ref, converter.WithPlatform(platMC))
123129
if err != nil {
124130
if len(options.Platforms) == 0 {
125131
return fmt.Errorf("failed to create a tmp single-platform image %q: %w", pushRef, err)
@@ -132,7 +138,7 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
132138

133139
if options.Estargz {
134140
pushRef = ref + "-tmp-esgz"
135-
esgzImg, err := converter.Convert(ctx, client, pushRef, ref, converter.WithPlatform(platMC), converter.WithLayerConvertFunc(eStargzConvertFunc()))
141+
esgzImg, err := nerdconverter.Convert(ctx, client, pushRef, ref, converter.WithPlatform(platMC), converter.WithLayerConvertFunc(eStargzConvertFunc()))
136142
if err != nil {
137143
return fmt.Errorf("failed to convert to eStargz: %v", err)
138144
}

pkg/cmd/image/remove.go

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ func Remove(ctx context.Context, client *containerd.Client, args []string, optio
7979

8080
if cid, ok := runningImages[found.Image.Name]; ok {
8181
if options.Force {
82+
// FIXME: this is suspicious, but passing the opt seem to break some tests
83+
// if err = is.Delete(ctx, found.Image.Name, delOpts...); err != nil {
8284
if err = is.Delete(ctx, found.Image.Name); err != nil {
8385
return err
8486
}
@@ -126,6 +128,8 @@ func Remove(ctx context.Context, client *containerd.Client, args []string, optio
126128

127129
if cid, ok := runningImages[found.Image.Name]; ok {
128130
if options.Force {
131+
// FIXME: this is suspicious, but passing the opt seem to break some tests
132+
// if err = is.Delete(ctx, found.Image.Name, delOpts...); err != nil {
129133
if err = is.Delete(ctx, found.Image.Name); err != nil {
130134
return false, err
131135
}

pkg/cmd/image/tag.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222

2323
containerd "github.com/containerd/containerd/v2/client"
24+
"github.com/containerd/containerd/v2/core/images"
2425
"github.com/containerd/errdefs"
2526
"github.com/containerd/log"
2627

@@ -81,7 +82,7 @@ func Tag(ctx context.Context, client *containerd.Client, options types.ImageTagO
8182
img.Name = parsedReference.String()
8283
if _, err = imageService.Create(ctx, img); err != nil {
8384
if errdefs.IsAlreadyExists(err) {
84-
if err = imageService.Delete(ctx, img.Name); err != nil {
85+
if err = imageService.Delete(ctx, img.Name, images.SynchronousDelete()); err != nil {
8586
return err
8687
}
8788
if _, err = imageService.Create(ctx, img); err != nil {

pkg/imgutil/converter/convert.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package converter
18+
19+
import (
20+
"context"
21+
22+
"github.com/containerd/containerd/v2/core/images"
23+
"github.com/containerd/containerd/v2/core/images/converter"
24+
)
25+
26+
// Something seems wrong in converter.Convert.
27+
// When dstRef != srcRef, convert will first forcefully delete dstRef,
28+
// *asynchronously*, then create the image.
29+
// This seems to cause a race conditions, and the deletion may kick in after the creation.
30+
// This here is to workaround the bug, by manually creating the image first,
31+
// then converting it in place (which avoid the problematic code-path).
32+
// See containerd upstream discussion https://github.com/containerd/containerd/pull/11628 and
33+
// nerdctl issues:
34+
// https://github.com/containerd/nerdctl/issues/3509#issuecomment-2398236766
35+
// https://github.com/containerd/nerdctl/issues/3513
36+
// Note this should be remove if/when containerd merges in a fix.
37+
38+
func Convert(ctx context.Context, client converter.Client, dstRef, srcRef string, opts ...converter.Opt) (*images.Image, error) {
39+
imageService := client.ImageService()
40+
41+
img, err := imageService.Get(ctx, srcRef)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
img.Name = dstRef
47+
48+
_ = imageService.Delete(ctx, img.Name, images.SynchronousDelete())
49+
50+
if _, err = imageService.Create(ctx, img); err != nil {
51+
return nil, err
52+
}
53+
54+
return converter.Convert(ctx, client, dstRef, dstRef, opts...)
55+
}

0 commit comments

Comments
 (0)