2017-05-27 06:12:13 +00:00
|
|
|
package cache
|
2017-05-26 00:16:32 +00:00
|
|
|
|
|
|
|
import (
|
2019-07-22 21:43:16 +00:00
|
|
|
"archive/tar"
|
|
|
|
"bytes"
|
|
|
|
"compress/gzip"
|
2017-05-26 18:56:12 +00:00
|
|
|
"context"
|
2019-07-22 21:43:16 +00:00
|
|
|
"io"
|
2017-05-26 00:16:32 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2017-05-26 17:20:41 +00:00
|
|
|
"path/filepath"
|
2020-07-27 17:24:31 +00:00
|
|
|
"runtime"
|
2017-05-26 00:16:32 +00:00
|
|
|
"testing"
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
"github.com/containerd/containerd/content"
|
|
|
|
"github.com/containerd/containerd/content/local"
|
2019-09-18 00:18:32 +00:00
|
|
|
"github.com/containerd/containerd/diff/apply"
|
2019-07-22 21:43:16 +00:00
|
|
|
"github.com/containerd/containerd/leases"
|
|
|
|
ctdmetadata "github.com/containerd/containerd/metadata"
|
2017-06-13 23:01:47 +00:00
|
|
|
"github.com/containerd/containerd/namespaces"
|
2017-12-28 07:07:13 +00:00
|
|
|
"github.com/containerd/containerd/snapshots"
|
2018-04-03 09:37:16 +00:00
|
|
|
"github.com/containerd/containerd/snapshots/native"
|
2017-07-05 02:00:27 +00:00
|
|
|
"github.com/moby/buildkit/cache/metadata"
|
2017-07-25 22:14:46 +00:00
|
|
|
"github.com/moby/buildkit/client"
|
2017-06-22 20:15:46 +00:00
|
|
|
"github.com/moby/buildkit/snapshot"
|
2019-07-22 21:43:16 +00:00
|
|
|
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
|
|
|
|
"github.com/moby/buildkit/util/leaseutil"
|
2020-05-13 15:37:27 +00:00
|
|
|
digest "github.com/opencontainers/go-digest"
|
2019-07-22 21:43:16 +00:00
|
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
2017-05-26 17:59:33 +00:00
|
|
|
"github.com/pkg/errors"
|
2017-07-14 18:59:31 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-07-22 21:43:16 +00:00
|
|
|
bolt "go.etcd.io/bbolt"
|
2017-05-26 00:16:32 +00:00
|
|
|
)
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
type cmOpt struct {
|
|
|
|
snapshotterName string
|
|
|
|
snapshotter snapshots.Snapshotter
|
|
|
|
tmpdir string
|
|
|
|
}
|
|
|
|
|
|
|
|
type cmOut struct {
|
|
|
|
manager Manager
|
|
|
|
lm leases.Manager
|
|
|
|
cs content.Store
|
|
|
|
}
|
|
|
|
|
|
|
|
func newCacheManager(ctx context.Context, opt cmOpt) (co *cmOut, cleanup func() error, err error) {
|
|
|
|
ns, ok := namespaces.Namespace(ctx)
|
|
|
|
if !ok {
|
|
|
|
return nil, nil, errors.Errorf("namespace required for test")
|
|
|
|
}
|
|
|
|
|
|
|
|
if opt.snapshotterName == "" {
|
|
|
|
opt.snapshotterName = "native"
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defers := make([]func() error, 0)
|
|
|
|
cleanup = func() error {
|
|
|
|
var err error
|
|
|
|
for i := range defers {
|
|
|
|
if err1 := defers[len(defers)-1-i](); err1 != nil && err == nil {
|
|
|
|
err = err1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
cleanup()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
if opt.tmpdir == "" {
|
|
|
|
defers = append(defers, func() error {
|
|
|
|
return os.RemoveAll(tmpdir)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
os.RemoveAll(tmpdir)
|
|
|
|
tmpdir = opt.tmpdir
|
|
|
|
}
|
|
|
|
|
|
|
|
if opt.snapshotter == nil {
|
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
opt.snapshotter = snapshotter
|
|
|
|
}
|
|
|
|
|
|
|
|
md, err := metadata.NewStore(filepath.Join(tmpdir, "metadata.db"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
store, err := local.NewStore(tmpdir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
db, err := bolt.Open(filepath.Join(tmpdir, "containerdmeta.db"), 0644, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
defers = append(defers, func() error {
|
|
|
|
return db.Close()
|
|
|
|
})
|
|
|
|
|
|
|
|
mdb := ctdmetadata.NewDB(db, store, map[string]snapshots.Snapshotter{
|
|
|
|
opt.snapshotterName: opt.snapshotter,
|
|
|
|
})
|
|
|
|
if err := mdb.Init(context.TODO()); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2019-09-30 23:38:02 +00:00
|
|
|
lm := ctdmetadata.NewLeaseManager(mdb)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
cm, err := NewManager(ManagerOpt{
|
|
|
|
Snapshotter: snapshot.FromContainerdSnapshotter(opt.snapshotterName, containerdsnapshot.NSSnapshotter(ns, mdb.Snapshotter(opt.snapshotterName)), nil),
|
|
|
|
MetadataStore: md,
|
|
|
|
ContentStore: mdb.ContentStore(),
|
|
|
|
LeaseManager: leaseutil.WithNamespace(lm, ns),
|
|
|
|
GarbageCollect: mdb.GarbageCollect,
|
2019-09-18 00:18:32 +00:00
|
|
|
Applier: apply.NewFileSystemApplier(mdb.ContentStore()),
|
2019-07-22 21:43:16 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return &cmOut{
|
|
|
|
manager: cm,
|
|
|
|
lm: lm,
|
|
|
|
cs: mdb.ContentStore(),
|
|
|
|
}, cleanup, nil
|
|
|
|
}
|
|
|
|
|
2017-05-27 06:12:13 +00:00
|
|
|
func TestManager(t *testing.T) {
|
2017-12-09 02:19:08 +00:00
|
|
|
t.Parallel()
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
2017-05-26 00:16:32 +00:00
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 00:16:32 +00:00
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
2018-04-03 09:37:16 +00:00
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
2017-11-06 09:44:23 +00:00
|
|
|
require.NoError(t, err)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer cleanup()
|
|
|
|
cm := co.manager
|
2017-05-26 00:16:32 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
_, err = cm.Get(ctx, "foobar")
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2017-05-26 00:34:59 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 0, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-07-20 22:55:24 +00:00
|
|
|
active, err := cm.New(ctx, nil, CachePolicyRetain)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:20:41 +00:00
|
|
|
|
2017-07-18 06:08:22 +00:00
|
|
|
m, err := active.Mount(ctx, false)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:20:41 +00:00
|
|
|
|
|
|
|
lm := snapshot.LocalMounter(m)
|
|
|
|
target, err := lm.Mount()
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:20:41 +00:00
|
|
|
|
|
|
|
fi, err := os.Stat(target)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fi.IsDir(), true)
|
2017-05-26 17:20:41 +00:00
|
|
|
|
|
|
|
err = lm.Unmount()
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:20:41 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, ErrLocked))
|
2017-05-26 17:59:33 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
snap, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
2017-05-26 17:59:33 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, ErrLocked))
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
err = snap.Release(ctx)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 0, 1)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
active, err = cm.GetMutable(ctx, active.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
snap, err = active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
2017-05-26 17:59:33 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2018-07-11 22:02:58 +00:00
|
|
|
err = snap.Finalize(ctx, true)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
err = snap.Release(ctx)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:59:33 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errNotFound))
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
_, err = cm.GetMutable(ctx, snap.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errInvalid))
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
snap, err = cm.Get(ctx, snap.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
snap2, err := cm.Get(ctx, snap.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
err = snap.Release(ctx)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 18:56:12 +00:00
|
|
|
|
2017-07-20 22:55:24 +00:00
|
|
|
active2, err := cm.New(ctx, snap2, CachePolicyRetain)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 20:45:01 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
snap3, err := active2.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
2017-05-26 20:45:01 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
err = snap2.Release(ctx)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 20:45:01 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-06-13 23:01:47 +00:00
|
|
|
err = snap3.Release(ctx)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 17:59:33 +00:00
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
checkDiskUsage(ctx, t, cm, 0, 2)
|
2017-05-26 21:17:38 +00:00
|
|
|
|
2017-12-27 01:22:50 +00:00
|
|
|
buf := pruneResultBuffer()
|
2018-07-26 00:20:57 +00:00
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
2017-12-27 01:22:50 +00:00
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 0)
|
|
|
|
|
|
|
|
require.Equal(t, len(buf.all), 2)
|
|
|
|
|
2017-05-26 00:16:32 +00:00
|
|
|
err = cm.Close()
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-12-27 01:22:50 +00:00
|
|
|
|
|
|
|
dirs, err := ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dirs))
|
|
|
|
}
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
func TestSnapshotExtract(t *testing.T) {
|
2020-07-27 17:24:31 +00:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Depends on unimplemented containerd bind-mount support on Windows")
|
|
|
|
}
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
t.Parallel()
|
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
cm := co.manager
|
|
|
|
|
|
|
|
b, desc, err := mapToBlob(map[string]string{"foo": "bar"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref1", bytes.NewBuffer(b), desc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap, err := cm.GetByBlob(ctx, desc, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, false, snap.Info().Extracted)
|
|
|
|
|
|
|
|
b2, desc2, err := mapToBlob(map[string]string{"foo": "bar123"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref1", bytes.NewBuffer(b2), desc2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap2, err := cm.GetByBlob(ctx, desc2, snap)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
size, err := snap2.Size(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(len(b2)), size)
|
|
|
|
|
|
|
|
require.Equal(t, false, snap2.Info().Extracted)
|
|
|
|
|
|
|
|
dirs, err := ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 2)
|
|
|
|
|
|
|
|
err = snap2.Extract(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, true, snap.Info().Extracted)
|
|
|
|
require.Equal(t, true, snap2.Info().Extracted)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
|
|
|
buf := pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
|
|
|
require.Equal(t, len(buf.all), 0)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 2)
|
|
|
|
|
|
|
|
id := snap.ID()
|
|
|
|
|
|
|
|
err = snap.Release(context.TODO())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
buf = pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
|
|
|
snap, err = cm.Get(ctx, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
|
|
|
err = snap2.Release(context.TODO())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 1, 1)
|
|
|
|
|
|
|
|
buf = pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
|
|
|
|
|
|
|
require.Equal(t, len(buf.all), 1)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 1)
|
|
|
|
|
|
|
|
err = snap.Release(context.TODO())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
buf = pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 0)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExtractOnMutable(t *testing.T) {
|
2020-07-27 17:24:31 +00:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Depends on unimplemented containerd bind-mount support on Windows")
|
|
|
|
}
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
t.Parallel()
|
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
cm := co.manager
|
|
|
|
|
|
|
|
active, err := cm.New(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
b, desc, err := mapToBlob(map[string]string{"foo": "bar"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref1", bytes.NewBuffer(b), desc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
b2, desc2, err := mapToBlob(map[string]string{"foo2": "1"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref2", bytes.NewBuffer(b2), desc2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-07-18 21:52:44 +00:00
|
|
|
_, err = cm.GetByBlob(ctx, desc2, snap)
|
2019-09-18 00:18:32 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
|
2020-05-28 20:46:33 +00:00
|
|
|
leaseCtx, done, err := leaseutil.WithLease(ctx, co.lm, leases.WithExpiration(0))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap.(*immutableRef).setBlob(leaseCtx, desc)
|
|
|
|
done(context.TODO())
|
2019-09-18 00:18:32 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-07-18 21:52:44 +00:00
|
|
|
snap2, err := cm.GetByBlob(ctx, desc2, snap)
|
2019-09-18 00:18:32 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap.Release(context.TODO())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, false, snap2.Info().Extracted)
|
|
|
|
|
|
|
|
size, err := snap2.Size(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(len(b2)), size)
|
|
|
|
|
|
|
|
dirs, err := ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 2)
|
|
|
|
|
|
|
|
err = snap2.Extract(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, true, snap.Info().Extracted)
|
|
|
|
require.Equal(t, true, snap2.Info().Extracted)
|
|
|
|
|
|
|
|
buf := pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
|
|
|
require.Equal(t, len(buf.all), 0)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
|
|
|
err = snap2.Release(context.TODO())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 2)
|
|
|
|
|
|
|
|
buf = pruneResultBuffer()
|
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 0)
|
|
|
|
|
|
|
|
require.Equal(t, len(buf.all), 2)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dirs))
|
|
|
|
|
|
|
|
checkNumBlobs(ctx, t, co.cs, 0)
|
|
|
|
}
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
func TestSetBlob(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer cleanup()
|
|
|
|
|
2020-05-28 20:46:33 +00:00
|
|
|
ctx, done, err := leaseutil.WithLease(ctx, co.lm, leaseutil.MakeTemporary)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer done(context.TODO())
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
cm := co.manager
|
|
|
|
|
|
|
|
active, err := cm.New(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
info := snap.Info()
|
|
|
|
require.Equal(t, "", string(info.DiffID))
|
|
|
|
require.Equal(t, "", string(info.Blob))
|
|
|
|
require.Equal(t, "", string(info.ChainID))
|
|
|
|
require.Equal(t, "", string(info.BlobChainID))
|
|
|
|
require.Equal(t, info.Extracted, true)
|
|
|
|
|
|
|
|
ctx, clean, err := leaseutil.WithLease(ctx, co.lm)
|
2019-09-19 21:38:25 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
defer clean(context.TODO())
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
b, desc, err := mapToBlob(map[string]string{"foo": "bar"})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref1", bytes.NewBuffer(b), desc)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-05-28 20:46:33 +00:00
|
|
|
err = snap.(*immutableRef).setBlob(ctx, ocispec.Descriptor{
|
2019-09-18 00:18:32 +00:00
|
|
|
Digest: digest.FromBytes([]byte("foobar")),
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"containerd.io/uncompressed": digest.FromBytes([]byte("foobar2")).String(),
|
|
|
|
},
|
|
|
|
})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
|
2020-05-28 20:46:33 +00:00
|
|
|
err = snap.(*immutableRef).setBlob(ctx, desc)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
info = snap.Info()
|
2019-09-18 00:18:32 +00:00
|
|
|
require.Equal(t, desc.Annotations["containerd.io/uncompressed"], string(info.DiffID))
|
|
|
|
require.Equal(t, desc.Digest, info.Blob)
|
|
|
|
require.Equal(t, desc.MediaType, info.MediaType)
|
|
|
|
require.Equal(t, info.DiffID, info.ChainID)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(desc.Digest+" "+info.DiffID)), info.BlobChainID)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.Equal(t, snap.ID(), info.SnapshotID)
|
|
|
|
require.Equal(t, info.Extracted, true)
|
|
|
|
|
|
|
|
active, err = cm.New(ctx, snap)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap2, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
b2, desc2, err := mapToBlob(map[string]string{"foo2": "bar2"})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref2", bytes.NewBuffer(b2), desc2)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-05-28 20:46:33 +00:00
|
|
|
err = snap2.(*immutableRef).setBlob(ctx, desc2)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
info2 := snap2.Info()
|
|
|
|
require.Equal(t, desc2.Annotations["containerd.io/uncompressed"], string(info2.DiffID))
|
|
|
|
require.Equal(t, desc2.Digest, info2.Blob)
|
|
|
|
require.Equal(t, desc2.MediaType, info2.MediaType)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(info.ChainID+" "+info2.DiffID)), info2.ChainID)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(info.BlobChainID+" "+digest.FromBytes([]byte(desc2.Digest+" "+info2.DiffID)))), info2.BlobChainID)
|
|
|
|
require.Equal(t, snap2.ID(), info2.SnapshotID)
|
|
|
|
require.Equal(t, info2.Extracted, true)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
b3, desc3, err := mapToBlob(map[string]string{"foo3": "bar3"})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref3", bytes.NewBuffer(b3), desc3)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
snap3, err := cm.GetByBlob(ctx, desc3, snap)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
info3 := snap3.Info()
|
|
|
|
require.Equal(t, desc3.Annotations["containerd.io/uncompressed"], string(info3.DiffID))
|
|
|
|
require.Equal(t, desc3.Digest, info3.Blob)
|
|
|
|
require.Equal(t, desc3.MediaType, info3.MediaType)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(info.ChainID+" "+info3.DiffID)), info3.ChainID)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(info.BlobChainID+" "+digest.FromBytes([]byte(desc3.Digest+" "+info3.DiffID)))), info3.BlobChainID)
|
|
|
|
require.Equal(t, string(info3.ChainID), info3.SnapshotID)
|
|
|
|
require.Equal(t, info3.Extracted, false)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
// snap4 is same as snap2
|
2019-09-18 00:18:32 +00:00
|
|
|
snap4, err := cm.GetByBlob(ctx, desc2, snap)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, snap2.ID(), snap4.ID())
|
|
|
|
|
|
|
|
// snap5 is same different blob but same diffID as snap2
|
2019-09-18 00:18:32 +00:00
|
|
|
b5, desc5, err := mapToBlob(map[string]string{"foo5": "bar5"})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
desc5.Annotations["containerd.io/uncompressed"] = info2.DiffID.String()
|
|
|
|
|
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref5", bytes.NewBuffer(b5), desc5)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
snap5, err := cm.GetByBlob(ctx, desc5, snap)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NotEqual(t, snap2.ID(), snap5.ID())
|
|
|
|
require.Equal(t, snap2.Info().SnapshotID, snap5.Info().SnapshotID)
|
2019-09-18 00:18:32 +00:00
|
|
|
require.Equal(t, info2.DiffID, snap5.Info().DiffID)
|
|
|
|
require.Equal(t, desc5.Digest, snap5.Info().Blob)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
require.Equal(t, snap2.Info().ChainID, snap5.Info().ChainID)
|
|
|
|
require.NotEqual(t, snap2.Info().BlobChainID, snap5.Info().BlobChainID)
|
2019-09-18 00:18:32 +00:00
|
|
|
require.Equal(t, digest.FromBytes([]byte(info.BlobChainID+" "+digest.FromBytes([]byte(desc5.Digest+" "+info2.DiffID)))), snap5.Info().BlobChainID)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
// snap6 is a child of snap3
|
2019-09-18 00:18:32 +00:00
|
|
|
b6, desc6, err := mapToBlob(map[string]string{"foo6": "bar6"})
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
err = content.WriteBlob(ctx, co.cs, "ref6", bytes.NewBuffer(b6), desc6)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
snap6, err := cm.GetByBlob(ctx, desc6, snap3)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
info6 := snap6.Info()
|
|
|
|
require.Equal(t, desc6.Annotations["containerd.io/uncompressed"], string(info6.DiffID))
|
|
|
|
require.Equal(t, desc6.Digest, info6.Blob)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(snap3.Info().ChainID+" "+info6.DiffID)), info6.ChainID)
|
|
|
|
require.Equal(t, digest.FromBytes([]byte(info3.BlobChainID+" "+digest.FromBytes([]byte(info6.Blob+" "+info6.DiffID)))), info6.BlobChainID)
|
|
|
|
require.Equal(t, string(info6.ChainID), info6.SnapshotID)
|
|
|
|
require.Equal(t, info6.Extracted, false)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
_, err = cm.GetByBlob(ctx, ocispec.Descriptor{
|
|
|
|
Digest: digest.FromBytes([]byte("notexist")),
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"containerd.io/uncompressed": digest.FromBytes([]byte("notexist")).String(),
|
|
|
|
},
|
|
|
|
}, snap3)
|
2019-07-22 21:43:16 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
clean(context.TODO())
|
|
|
|
|
|
|
|
//snap.SetBlob()
|
|
|
|
}
|
|
|
|
|
2017-12-27 01:22:50 +00:00
|
|
|
func TestPrune(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
2018-04-03 09:37:16 +00:00
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
2017-12-27 01:22:50 +00:00
|
|
|
require.NoError(t, err)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer cleanup()
|
|
|
|
cm := co.manager
|
2017-12-27 01:22:50 +00:00
|
|
|
|
|
|
|
active, err := cm.New(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
active, err = cm.New(ctx, snap, CachePolicyRetain)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap2, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
dirs, err := ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
2017-12-27 01:22:50 +00:00
|
|
|
// prune with keeping refs does nothing
|
|
|
|
buf := pruneResultBuffer()
|
2018-07-26 00:20:57 +00:00
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
2017-12-27 01:22:50 +00:00
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
require.Equal(t, len(buf.all), 0)
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
2017-12-27 01:22:50 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dirs))
|
|
|
|
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 1, 1)
|
|
|
|
|
|
|
|
// prune with keeping single refs deletes one
|
|
|
|
buf = pruneResultBuffer()
|
2018-07-26 00:20:57 +00:00
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
2017-12-27 01:22:50 +00:00
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 1, 0)
|
|
|
|
require.Equal(t, len(buf.all), 1)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dirs))
|
|
|
|
|
|
|
|
err = snap.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
active, err = cm.New(ctx, snap, CachePolicyRetain)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
snap2, err = active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
|
|
|
|
// prune with parent released does nothing
|
|
|
|
buf = pruneResultBuffer()
|
2018-07-26 00:20:57 +00:00
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
2017-12-27 01:22:50 +00:00
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 2, 0)
|
|
|
|
require.Equal(t, len(buf.all), 0)
|
|
|
|
|
|
|
|
// releasing last reference
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 2)
|
|
|
|
|
|
|
|
buf = pruneResultBuffer()
|
2018-07-26 00:20:57 +00:00
|
|
|
err = cm.Prune(ctx, buf.C, client.PruneInfo{})
|
2017-12-27 01:22:50 +00:00
|
|
|
buf.close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
checkDiskUsage(ctx, t, cm, 0, 0)
|
|
|
|
require.Equal(t, len(buf.all), 2)
|
|
|
|
|
|
|
|
dirs, err = ioutil.ReadDir(filepath.Join(tmpdir, "snapshots/snapshots"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dirs))
|
2017-07-14 18:59:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestLazyCommit(t *testing.T) {
|
2017-12-09 02:19:08 +00:00
|
|
|
t.Parallel()
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
|
|
|
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "cachemanager")
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
|
2018-04-03 09:37:16 +00:00
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
2017-11-06 09:44:23 +00:00
|
|
|
require.NoError(t, err)
|
2019-07-22 21:43:16 +00:00
|
|
|
|
|
|
|
co, cleanup, err := newCacheManager(ctx, cmOpt{
|
|
|
|
tmpdir: tmpdir,
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
cm := co.manager
|
2017-07-14 18:59:31 +00:00
|
|
|
|
2017-07-20 22:55:24 +00:00
|
|
|
active, err := cm.New(ctx, nil, CachePolicyRetain)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// after commit mutable is locked
|
|
|
|
snap, err := active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, ErrLocked))
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
// immutable refs still work
|
|
|
|
snap2, err := cm.Get(ctx, snap.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, snap.ID(), snap2.ID())
|
|
|
|
|
|
|
|
err = snap.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// immutable work after final release as well
|
|
|
|
snap, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, snap.ID(), snap2.ID())
|
2017-07-19 23:39:32 +00:00
|
|
|
|
|
|
|
// active can't be get while immutable is held
|
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, ErrLocked))
|
2017-07-19 23:39:32 +00:00
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
err = snap.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// after release mutable becomes available again
|
|
|
|
active2, err := cm.GetMutable(ctx, active.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, active2.ID(), active.ID())
|
|
|
|
|
|
|
|
// because ref was took mutable old immutable are cleared
|
|
|
|
_, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errNotFound))
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
snap, err = active2.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// this time finalize commit
|
2018-07-11 22:02:58 +00:00
|
|
|
err = snap.Finalize(ctx, true)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// mutable is gone after finalize
|
|
|
|
_, err = cm.GetMutable(ctx, active2.ID())
|
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errNotFound))
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
// immutable still works
|
|
|
|
snap2, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, snap.ID(), snap2.ID())
|
|
|
|
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// test restarting after commit
|
2017-07-20 22:55:24 +00:00
|
|
|
active, err = cm.New(ctx, nil, CachePolicyRetain)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// after commit mutable is locked
|
|
|
|
snap, err = active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = cm.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
cleanup()
|
|
|
|
|
2018-09-18 18:18:08 +00:00
|
|
|
// we can't close snapshotter and open it twice (especially, its internal bbolt store)
|
2019-07-22 21:43:16 +00:00
|
|
|
co, cleanup, err = newCacheManager(ctx, cmOpt{
|
|
|
|
tmpdir: tmpdir,
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
cm = co.manager
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
snap2, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
active, err = cm.GetMutable(ctx, active.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errNotFound))
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
snap, err = active.Commit(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = cm.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-07-22 21:43:16 +00:00
|
|
|
cleanup()
|
|
|
|
|
|
|
|
co, cleanup, err = newCacheManager(ctx, cmOpt{
|
|
|
|
tmpdir: tmpdir,
|
|
|
|
snapshotter: snapshotter,
|
|
|
|
snapshotterName: "native",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer cleanup()
|
|
|
|
cm = co.manager
|
2017-07-14 18:59:31 +00:00
|
|
|
|
|
|
|
snap2, err = cm.Get(ctx, snap.ID())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2018-07-11 22:02:58 +00:00
|
|
|
err = snap2.Finalize(ctx, true)
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = snap2.Release(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-07-18 21:52:44 +00:00
|
|
|
_, err = cm.GetMutable(ctx, active.ID())
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Error(t, err)
|
2020-04-19 05:17:47 +00:00
|
|
|
require.Equal(t, true, errors.Is(err, errNotFound))
|
2017-07-14 18:59:31 +00:00
|
|
|
}
|
|
|
|
|
2017-11-17 02:09:35 +00:00
|
|
|
func checkDiskUsage(ctx context.Context, t *testing.T, cm Manager, inuse, unused int) {
|
2017-07-25 22:14:46 +00:00
|
|
|
du, err := cm.DiskUsage(ctx, client.DiskUsageInfo{})
|
2017-07-14 18:59:31 +00:00
|
|
|
require.NoError(t, err)
|
2017-05-26 21:17:38 +00:00
|
|
|
var inuseActual, unusedActual int
|
|
|
|
for _, r := range du {
|
|
|
|
if r.InUse {
|
|
|
|
inuseActual++
|
|
|
|
} else {
|
|
|
|
unusedActual++
|
|
|
|
}
|
|
|
|
}
|
2017-07-14 18:59:31 +00:00
|
|
|
require.Equal(t, inuse, inuseActual)
|
|
|
|
require.Equal(t, unused, unusedActual)
|
2017-05-26 21:17:38 +00:00
|
|
|
}
|
2017-12-27 01:22:50 +00:00
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
func checkNumBlobs(ctx context.Context, t *testing.T, cs content.Store, expected int) {
|
|
|
|
c := 0
|
|
|
|
err := cs.Walk(ctx, func(_ content.Info) error {
|
|
|
|
c++
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expected, c)
|
|
|
|
}
|
|
|
|
|
2017-12-27 01:22:50 +00:00
|
|
|
func pruneResultBuffer() *buf {
|
|
|
|
b := &buf{C: make(chan client.UsageInfo), closed: make(chan struct{})}
|
|
|
|
go func() {
|
|
|
|
for c := range b.C {
|
|
|
|
b.all = append(b.all, c)
|
|
|
|
}
|
|
|
|
close(b.closed)
|
|
|
|
}()
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
type buf struct {
|
|
|
|
C chan client.UsageInfo
|
|
|
|
closed chan struct{}
|
|
|
|
all []client.UsageInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *buf) close() {
|
|
|
|
close(b.C)
|
|
|
|
<-b.closed
|
|
|
|
}
|
2019-07-22 21:43:16 +00:00
|
|
|
|
2019-09-18 00:18:32 +00:00
|
|
|
func mapToBlob(m map[string]string) ([]byte, ocispec.Descriptor, error) {
|
2019-07-22 21:43:16 +00:00
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
gz := gzip.NewWriter(buf)
|
|
|
|
sha := digest.SHA256.Digester()
|
|
|
|
tw := tar.NewWriter(io.MultiWriter(sha.Hash(), gz))
|
|
|
|
|
|
|
|
for k, v := range m {
|
|
|
|
if err := tw.WriteHeader(&tar.Header{
|
|
|
|
Name: k,
|
|
|
|
Size: int64(len(v)),
|
|
|
|
}); err != nil {
|
2019-09-18 00:18:32 +00:00
|
|
|
return nil, ocispec.Descriptor{}, err
|
2019-07-22 21:43:16 +00:00
|
|
|
}
|
|
|
|
if _, err := tw.Write([]byte(v)); err != nil {
|
2019-09-18 00:18:32 +00:00
|
|
|
return nil, ocispec.Descriptor{}, err
|
2019-07-22 21:43:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := tw.Close(); err != nil {
|
2019-09-18 00:18:32 +00:00
|
|
|
return nil, ocispec.Descriptor{}, err
|
2019-07-22 21:43:16 +00:00
|
|
|
}
|
|
|
|
if err := gz.Close(); err != nil {
|
2019-09-18 00:18:32 +00:00
|
|
|
return nil, ocispec.Descriptor{}, err
|
2019-07-22 21:43:16 +00:00
|
|
|
}
|
2019-09-18 00:18:32 +00:00
|
|
|
return buf.Bytes(), ocispec.Descriptor{
|
|
|
|
Digest: digest.FromBytes(buf.Bytes()),
|
|
|
|
MediaType: ocispec.MediaTypeImageLayerGzip,
|
|
|
|
Size: int64(buf.Len()),
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"containerd.io/uncompressed": sha.Digest().String(),
|
|
|
|
},
|
|
|
|
}, nil
|
2019-07-22 21:43:16 +00:00
|
|
|
}
|