Skip to content

Commit 40b425a

Browse files
committed
fix premature exits in image save
Signed-off-by: Arjun Yogidas <arjunry@amazon.com>
1 parent 478c649 commit 40b425a

1 file changed

Lines changed: 25 additions & 4 deletions

File tree

pkg/cmd/image/save.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,43 @@ func Save(ctx context.Context, client *containerd.Client, images []string, optio
101101
storeOpts = append(storeOpts, transferimage.WithExtraReference(imageRef))
102102
}
103103

104-
w := nopWriteCloser{options.Stdout}
104+
w := &syncWriteCloser{
105+
Writer: options.Stdout,
106+
done: make(chan struct{}),
107+
}
105108

106109
pf, done := transferutil.ProgressHandler(ctx, os.Stderr)
107110
defer done()
108111

109-
return client.Transfer(ctx,
112+
err = client.Transfer(ctx,
110113
transferimage.NewStore("", storeOpts...),
111114
tarchive.NewImageExportStream(w, "", exportOpts...),
112115
transfer.WithProgress(pf),
113116
)
117+
if err != nil {
118+
return err
119+
}
120+
121+
// Wait for the stream copy goroutine to finish writing before returning.
122+
// client.Transfer returns when the server-side export completes, but the
123+
// client-side goroutine in containerd's ImageExportStream.MarshalAny may
124+
// still be copying streamed data to the writer. Without this wait, the
125+
// caller may close the output file while the goroutine is still writing,
126+
// resulting in "file already closed" errors and a truncated tar archive.
127+
<-w.done
128+
129+
return nil
114130
}
115131

116-
type nopWriteCloser struct {
132+
// syncWriteCloser wraps an io.Writer and signals when Close is called,
133+
// allowing the caller to wait until the transfer stream goroutine has
134+
// finished writing all data.
135+
type syncWriteCloser struct {
117136
io.Writer
137+
done chan struct{}
118138
}
119139

120-
func (nopWriteCloser) Close() error {
140+
func (s *syncWriteCloser) Close() error {
141+
close(s.done)
121142
return nil
122143
}

0 commit comments

Comments
 (0)