diff --git a/snapshot/btrfs/btrfs_test.go b/snapshot/btrfs/btrfs_test.go index 2a1e9e748..5259ea765 100644 --- a/snapshot/btrfs/btrfs_test.go +++ b/snapshot/btrfs/btrfs_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot/testsuite" "github.com/containerd/containerd/testutil" @@ -42,7 +43,7 @@ func TestBtrfs(t *testing.T) { func TestBtrfsMounts(t *testing.T) { testutil.RequiresRoot(t) - ctx := context.Background() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-btrfs-test") // create temporary directory for mount point mountPoint, err := ioutil.TempDir("", "containerd-btrfs-test") diff --git a/snapshot/overlay/overlay_test.go b/snapshot/overlay/overlay_test.go index f80d11559..0a9252fa6 100644 --- a/snapshot/overlay/overlay_test.go +++ b/snapshot/overlay/overlay_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot/storage" "github.com/containerd/containerd/snapshot/testsuite" @@ -33,7 +34,7 @@ func TestOverlay(t *testing.T) { } func TestOverlayMounts(t *testing.T) { - ctx := context.TODO() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-overlay-test") root, err := ioutil.TempDir("", "overlay") if err != nil { t.Fatal(err) @@ -69,7 +70,7 @@ func TestOverlayMounts(t *testing.T) { } func TestOverlayCommit(t *testing.T) { - ctx := context.TODO() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-overlay-test") root, err := ioutil.TempDir("", "overlay") if err != nil { t.Fatal(err) @@ -98,7 +99,7 @@ func TestOverlayCommit(t *testing.T) { } func TestOverlayOverlayMount(t *testing.T) { - ctx := context.TODO() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-overlay-test") root, err := ioutil.TempDir("", "overlay") if err != nil { t.Fatal(err) @@ -186,7 +187,7 @@ func getParents(ctx context.Context, sn snapshot.Snapshotter, root, key string) func TestOverlayOverlayRead(t *testing.T) { testutil.RequiresRoot(t) - ctx := context.TODO() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-overlay-test") root, err := ioutil.TempDir("", "overlay") if err != nil { t.Fatal(err) @@ -238,7 +239,7 @@ func TestOverlayOverlayRead(t *testing.T) { } func TestOverlayView(t *testing.T) { - ctx := context.TODO() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-overlay-test") root, err := ioutil.TempDir("", "overlay") if err != nil { t.Fatal(err) diff --git a/snapshot/storage/bolt.go b/snapshot/storage/bolt.go index ba5e43e31..8be5245da 100644 --- a/snapshot/storage/bolt.go +++ b/snapshot/storage/bolt.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/boltdb/bolt" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" db "github.com/containerd/containerd/snapshot/storage/proto" "github.com/gogo/protobuf/proto" @@ -136,7 +137,7 @@ func CreateActive(ctx context.Context, key, parent string, readonly bool) (a Act return snapshot.ErrSnapshotExist } - id, err := bkt.NextSequence() + id, err := nextSequence(ctx) if err != nil { return errors.Wrap(err, "unable to get identifier") } @@ -309,28 +310,68 @@ func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) ( return } +// nextSequence maintains the snapshot ids in the same space across namespaces +// to avoid collisions on the filesystem, which is typically not namespace +// aware. This will also be useful to ensure that snapshots can be used across +// namespaces in the future, by projecting parent relationships into an +// alternate namespace without fixing up identifiers. +func nextSequence(ctx context.Context) (uint64, error) { + t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) + if !ok { + return 0, ErrNoTransaction + } + + bkt := t.tx.Bucket(bucketKeyStorageVersion) + if bkt == nil { + return 0, errors.New("version bucket required for sequence") + } + + return bkt.NextSequence() +} + func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { + namespace, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) if !ok { return ErrNoTransaction } - bkt := t.tx.Bucket(bucketKeyStorageVersion) - if bkt == nil { + nbkt := t.tx.Bucket(bucketKeyStorageVersion) + if nbkt == nil { return errors.Wrap(snapshot.ErrSnapshotNotExist, "bucket does not exist") } + + bkt := nbkt.Bucket([]byte(namespace)) + if bkt == nil { + return errors.Wrap(snapshot.ErrSnapshotNotExist, "namespace not available in snapshotter") + } + return fn(ctx, bkt.Bucket(bucketKeySnapshot), bkt.Bucket(bucketKeyParents)) } func createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { + namespace, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) if !ok { return ErrNoTransaction } - bkt, err := t.tx.CreateBucketIfNotExists(bucketKeyStorageVersion) + nbkt, err := t.tx.CreateBucketIfNotExists(bucketKeyStorageVersion) if err != nil { return errors.Wrap(err, "failed to create version bucket") } + + bkt, err := nbkt.CreateBucketIfNotExists([]byte(namespace)) + if err != nil { + return err + } + sbkt, err := bkt.CreateBucketIfNotExists(bucketKeySnapshot) if err != nil { return errors.Wrap(err, "failed to create snapshots bucket") diff --git a/snapshot/storage/metastore_test.go b/snapshot/storage/metastore_test.go index 83772257b..ca800db45 100644 --- a/snapshot/storage/metastore_test.go +++ b/snapshot/storage/metastore_test.go @@ -6,6 +6,7 @@ import ( "os" "testing" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -44,7 +45,7 @@ func MetaStoreSuite(t *testing.T, name string, meta func(root string) (*MetaStor // makeTest creates a testsuite with a writable transaction func makeTest(t *testing.T, name string, metaFn metaFactory, fn testFunc) func(t *testing.T) { return func(t *testing.T) { - ctx := context.Background() + ctx := namespaces.WithNamespace(context.Background(), "testing-snapshot-metadata") tmpDir, err := ioutil.TempDir("", "metastore-test-"+name+"-") if err != nil { t.Fatal(err) diff --git a/snapshot/testsuite/testsuite.go b/snapshot/testsuite/testsuite.go index f447802d0..fee6bcdff 100644 --- a/snapshot/testsuite/testsuite.go +++ b/snapshot/testsuite/testsuite.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/fs/fstest" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/testutil" "github.com/stretchr/testify/assert" @@ -26,7 +27,7 @@ func SnapshotterSuite(t *testing.T, name string, snapshotterFn func(ctx context. func makeTest(t *testing.T, name string, snapshotterFn func(ctx context.Context, root string) (snapshot.Snapshotter, func(), error), fn func(ctx context.Context, t *testing.T, snapshotter snapshot.Snapshotter, work string)) func(t *testing.T) { return func(t *testing.T) { - ctx := context.Background() + ctx := namespaces.WithNamespace(context.Background(), "snapshotter-test") restoreMask := clearMask() defer restoreMask() // Make two directories: a snapshotter root and a play area for the tests: