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 <dnephin@gmail.com>
This commit is contained in:
Daniel Nephin 2017-12-13 18:24:08 -05:00
parent 03bc5e974d
commit 9184908075
3 changed files with 45 additions and 1 deletions

View File

@ -77,7 +77,7 @@ func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected dige
r, err = seekReader(r, ws.Offset, size) r, err = seekReader(r, ws.Offset, size)
if err != nil { if err != nil {
if !isUnseekable(err) { if !isUnseekable(err) {
return errors.Wrapf(err, "unabled to resume write to %v", ws.Ref) return errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
} }
// reader is unseekable, try to move the writer back to the start. // reader is unseekable, try to move the writer back to the start.

View File

@ -22,6 +22,7 @@ import (
"github.com/containerd/containerd/content/testsuite" "github.com/containerd/containerd/content/testsuite"
"github.com/containerd/containerd/testutil" "github.com/containerd/containerd/testutil"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/require"
) )
type memoryLabelStore struct { type memoryLabelStore struct {
@ -335,3 +336,42 @@ func checkWrite(ctx context.Context, t checker, cs content.Store, dgst digest.Di
return dgst return dgst
} }
func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "test-local-content-store-recover")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
cs, err := NewStore(tmpdir)
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ref := "ref"
content := []byte("this is the content")
total := int64(len(content))
setupIncompleteWrite(ctx, t, cs, ref, total)
writer, err := cs.Writer(ctx, ref, total, "")
require.NoError(t, err)
require.NoError(t, writer.Truncate(0))
_, err = writer.Write(content)
require.NoError(t, err)
dgst := digest.FromBytes(content)
err = writer.Commit(ctx, total, dgst)
require.NoError(t, err)
}
func setupIncompleteWrite(ctx context.Context, t *testing.T, cs content.Store, ref string, total int64) {
writer, err := cs.Writer(ctx, ref, total, "")
require.NoError(t, err)
_, err = writer.Write([]byte("bad data"))
require.NoError(t, err)
require.NoError(t, writer.Close())
}

View File

@ -2,6 +2,7 @@ package local
import ( import (
"context" "context"
"io"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -167,5 +168,8 @@ func (w *writer) Truncate(size int64) error {
} }
w.offset = 0 w.offset = 0
w.digester.Hash().Reset() w.digester.Hash().Reset()
if _, err := w.fp.Seek(0, io.SeekStart); err != nil {
return err
}
return w.fp.Truncate(0) return w.fp.Truncate(0)
} }