Skip to content

Commit 63e1963

Browse files
dnephincrosbymichael
authored andcommitted
Fix image pull after a failure
When resuming from a failed pull writer.Truncate() was not seeking to the proper position in the file. This caused writes to happen after the previously written content, instead of at the start of the file. Signed-off-by: Daniel Nephin <[email protected]>
1 parent dba5fa0 commit 63e1963

3 files changed

Lines changed: 45 additions & 1 deletion

File tree

content/helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected dige
7777
r, err = seekReader(r, ws.Offset, size)
7878
if err != nil {
7979
if !isUnseekable(err) {
80-
return errors.Wrapf(err, "unabled to resume write to %v", ws.Ref)
80+
return errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
8181
}
8282

8383
// reader is unseekable, try to move the writer back to the start.

content/local/store_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/containerd/containerd/content/testsuite"
2323
"github.com/containerd/containerd/testutil"
2424
"github.com/opencontainers/go-digest"
25+
"github.com/stretchr/testify/require"
2526
)
2627

2728
type memoryLabelStore struct {
@@ -335,3 +336,42 @@ func checkWrite(ctx context.Context, t checker, cs content.Store, dgst digest.Di
335336

336337
return dgst
337338
}
339+
340+
func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
341+
tmpdir, err := ioutil.TempDir("", "test-local-content-store-recover")
342+
require.NoError(t, err)
343+
defer os.RemoveAll(tmpdir)
344+
345+
cs, err := NewStore(tmpdir)
346+
require.NoError(t, err)
347+
348+
ctx, cancel := context.WithCancel(context.Background())
349+
defer cancel()
350+
351+
ref := "ref"
352+
content := []byte("this is the content")
353+
total := int64(len(content))
354+
setupIncompleteWrite(ctx, t, cs, ref, total)
355+
356+
writer, err := cs.Writer(ctx, ref, total, "")
357+
require.NoError(t, err)
358+
359+
require.NoError(t, writer.Truncate(0))
360+
361+
_, err = writer.Write(content)
362+
require.NoError(t, err)
363+
364+
dgst := digest.FromBytes(content)
365+
err = writer.Commit(ctx, total, dgst)
366+
require.NoError(t, err)
367+
}
368+
369+
func setupIncompleteWrite(ctx context.Context, t *testing.T, cs content.Store, ref string, total int64) {
370+
writer, err := cs.Writer(ctx, ref, total, "")
371+
require.NoError(t, err)
372+
373+
_, err = writer.Write([]byte("bad data"))
374+
require.NoError(t, err)
375+
376+
require.NoError(t, writer.Close())
377+
}

content/local/writer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package local
22

33
import (
44
"context"
5+
"io"
56
"os"
67
"path/filepath"
78
"runtime"
@@ -167,5 +168,8 @@ func (w *writer) Truncate(size int64) error {
167168
}
168169
w.offset = 0
169170
w.digester.Hash().Reset()
171+
if _, err := w.fp.Seek(0, io.SeekStart); err != nil {
172+
return err
173+
}
170174
return w.fp.Truncate(0)
171175
}

0 commit comments

Comments
 (0)