Skip to content

Commit 75b7499

Browse files
committed
fix: fix load image failed
Signed-off-by: ningmingxiao <ning.mingxiao@zte.com.cn>
1 parent 0b388bb commit 75b7499

3 files changed

Lines changed: 134 additions & 25 deletions

File tree

cmd/nerdctl/image/image_load_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestLoadStdinFromPipe(t *testing.T) {
4040
Description: "TestLoadStdinFromPipe",
4141
Require: require.Linux,
4242
Setup: func(data test.Data, helpers test.Helpers) {
43-
identifier := data.Identifier()
43+
identifier := "testLoadStdinFromPipe"
4444
helpers.Ensure("pull", "--quiet", testutil.CommonImage)
4545
helpers.Ensure("tag", testutil.CommonImage, identifier)
4646
helpers.Ensure("save", identifier, "-o", filepath.Join(data.Temp().Path(), "common.tar"))
@@ -57,7 +57,9 @@ func TestLoadStdinFromPipe(t *testing.T) {
5757
return cmd
5858
},
5959
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
60-
identifier := data.Identifier()
60+
// fix me see https://github.com/containerd/containerd/issues/13097
61+
// container image can't include dash
62+
identifier := "testLoadStdinFromPipe"
6163
return &test.Expected{
6264
Output: expect.All(
6365
expect.Contains(identifier),

pkg/imgutil/load/load.go

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"os"
2424
"strings"
25+
"time"
2526

2627
containerd "github.com/containerd/containerd/v2/client"
2728
"github.com/containerd/containerd/v2/core/images"
@@ -82,35 +83,16 @@ func FromArchive(ctx context.Context, client *containerd.Client, options types.I
8283
storeOpts = append(storeOpts, transferimage.WithPlatforms(platUnpack))
8384
}
8485
storeOpts = append(storeOpts, transferimage.WithUnpack(platUnpack, options.GOptions.Snapshotter))
85-
storeOpts = append(storeOpts, transferimage.WithDigestRef("import", true, true))
86-
87-
var loadedImages []images.Image
88-
pf, done := transferutil.ProgressHandler(ctx, options.Stdout)
86+
storeOpts = append(storeOpts, transferimage.WithNamedPrefix(fmt.Sprintf("import-%s", time.Now().Format("2006-01-02")), true))
8987

88+
pf, done, loadedImages := transferutil.ProgressHandlerLoadImage(ctx, client, beforeSet, options)
9089
err = client.Transfer(ctx,
9190
tarchive.NewImageImportStream(options.Stdin, ""),
9291
transferimage.NewStore("", storeOpts...),
93-
transfer.WithProgress(func(p transfer.Progress) {
94-
if p.Event == "saved" {
95-
if img, err := imageService.Get(ctx, p.Name); err == nil {
96-
if !beforeSet[img.Name] {
97-
loadedImages = append(loadedImages, img)
98-
}
99-
}
100-
}
101-
pf(p)
102-
}),
92+
transfer.WithProgress(pf),
10393
)
104-
10594
done()
106-
107-
if !options.Quiet {
108-
for _, img := range loadedImages {
109-
fmt.Fprintf(options.Stdout, "Loaded image: %s\n", img.Name)
110-
}
111-
}
112-
113-
return loadedImages, err
95+
return *loadedImages, err
11496
}
11597

11698
// FromOCIArchive loads and unpacks the images from the OCI formatted archive at the provided file system path.

pkg/transferutil/progress.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ import (
2525

2626
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2727

28+
containerd "github.com/containerd/containerd/v2/client"
29+
"github.com/containerd/containerd/v2/core/images"
2830
"github.com/containerd/containerd/v2/core/transfer"
2931
"github.com/containerd/containerd/v2/pkg/progress"
32+
33+
"github.com/containerd/nerdctl/v2/pkg/api/types"
3034
)
3135

3236
// From https://github.com/containerd/containerd/blob/v2.2.0-rc.0/cmd/ctr/commands/image/pull.go#L240-L473
@@ -156,6 +160,127 @@ func ProgressHandler(ctx context.Context, out io.Writer) (transfer.ProgressFunc,
156160
return progressFn, done
157161
}
158162

163+
func ProgressHandlerLoadImage(ctx context.Context, client *containerd.Client, beforeSet map[string]bool, options types.ImageLoadOptions) (transfer.ProgressFunc, func(), *[]images.Image) {
164+
ctx, cancel := context.WithCancel(ctx)
165+
var (
166+
fw = progress.NewWriter(options.Stdout)
167+
start = time.Now()
168+
statuses = map[string]*progressNode{}
169+
roots = []*progressNode{}
170+
pc = make(chan transfer.Progress, 5)
171+
status string
172+
closeC = make(chan struct{})
173+
loadedImages []images.Image
174+
imagesDisplay []string
175+
)
176+
177+
result := &loadedImages
178+
progressFn := func(p transfer.Progress) {
179+
select {
180+
case pc <- p:
181+
case <-ctx.Done():
182+
}
183+
}
184+
185+
done := func() {
186+
cancel()
187+
<-closeC
188+
if !options.Quiet {
189+
for _, img := range imagesDisplay {
190+
fmt.Fprintf(options.Stdout, "Loaded image: %s\n", img)
191+
}
192+
}
193+
}
194+
195+
go func() {
196+
defer close(closeC)
197+
for {
198+
select {
199+
case p := <-pc:
200+
if p.Name == "" {
201+
status = p.Event
202+
continue
203+
}
204+
if p.Event == "saved" {
205+
if img, err := client.ImageService().Get(ctx, p.Name); err == nil {
206+
if !beforeSet[img.Name] {
207+
loadedImages = append(loadedImages, img)
208+
}
209+
imagesDisplay = append(imagesDisplay, img.Name)
210+
}
211+
}
212+
if node, ok := statuses[p.Name]; !ok {
213+
node = &progressNode{
214+
Progress: p,
215+
root: true,
216+
}
217+
if len(p.Parents) == 0 {
218+
roots = append(roots, node)
219+
} else {
220+
var parents []string
221+
for _, parent := range p.Parents {
222+
pStatus, ok := statuses[parent]
223+
if ok {
224+
parents = append(parents, parent)
225+
pStatus.children = append(pStatus.children, node)
226+
node.root = false
227+
}
228+
}
229+
node.Progress.Parents = parents
230+
if node.root {
231+
roots = append(roots, node)
232+
}
233+
}
234+
statuses[p.Name] = node
235+
} else {
236+
if len(node.Progress.Parents) != len(p.Parents) {
237+
var parents []string
238+
var removeRoot bool
239+
for _, parent := range p.Parents {
240+
pStatus, ok := statuses[parent]
241+
if ok {
242+
parents = append(parents, parent)
243+
var found bool
244+
for _, child := range pStatus.children {
245+
if child.Progress.Name == p.Name {
246+
found = true
247+
break
248+
}
249+
}
250+
if !found {
251+
pStatus.children = append(pStatus.children, node)
252+
}
253+
if node.root {
254+
removeRoot = true
255+
}
256+
node.root = false
257+
}
258+
}
259+
p.Parents = parents
260+
// Check if needs to remove from root
261+
if removeRoot {
262+
for i := range roots {
263+
if roots[i] == node {
264+
roots = append(roots[:i], roots[i+1:]...)
265+
break
266+
}
267+
}
268+
}
269+
}
270+
node.Progress = p
271+
}
272+
273+
displayHierarchy(fw, status, roots, start)
274+
fw.Flush()
275+
276+
case <-ctx.Done():
277+
return
278+
}
279+
}
280+
}()
281+
return progressFn, done, result
282+
}
283+
159284
func displayHierarchy(w io.Writer, status string, roots []*progressNode, start time.Time) {
160285
total := displayNode(w, "", roots)
161286
for _, r := range roots {

0 commit comments

Comments
 (0)