Revert "Add shared content label to namespaces"
This reverts commit e692a01926
.
Signed-off-by: Cody Roseborough <cdr@amazon.com>
This commit is contained in:
parent
6e211a774f
commit
8dd36423b6
@ -232,7 +232,3 @@ The default is "shared". While this is largely the most desired policy, one can
|
|||||||
[plugins.bolt]
|
[plugins.bolt]
|
||||||
content_sharing_policy = "isolated"
|
content_sharing_policy = "isolated"
|
||||||
```
|
```
|
||||||
|
|
||||||
It is possible to share only the contents of a specific namespace by adding the label `containerd.io/namespace.shareable=true` to that namespace.
|
|
||||||
This will share the contents of the namespace even if the content sharing policy is set to isolated and make its images usable by all other namespaces.
|
|
||||||
If the label value is set to anything other than `true`, the namespace content will not be shared.
|
|
||||||
|
@ -19,7 +19,3 @@ package labels
|
|||||||
// LabelUncompressed is added to compressed layer contents.
|
// LabelUncompressed is added to compressed layer contents.
|
||||||
// The value is digest of the uncompressed content.
|
// The value is digest of the uncompressed content.
|
||||||
const LabelUncompressed = "containerd.io/uncompressed"
|
const LabelUncompressed = "containerd.io/uncompressed"
|
||||||
|
|
||||||
// LabelSharedNamespace is added to a namespace to allow that namespaces
|
|
||||||
// contents to be shared.
|
|
||||||
const LabelSharedNamespace = "containerd.io/namespace.shareable"
|
|
||||||
|
@ -115,7 +115,6 @@
|
|||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/containerd/containerd/labels"
|
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
@ -183,45 +182,6 @@ func createBucketIfNotExists(tx *bolt.Tx, keys ...[]byte) (*bolt.Bucket, error)
|
|||||||
return bkt, nil
|
return bkt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespacesBucketPath() []byte {
|
|
||||||
return bucketKeyVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNamespacesBucket(tx *bolt.Tx) *bolt.Bucket {
|
|
||||||
return getBucket(tx, namespacesBucketPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a namespace string and a bolt transaction
|
|
||||||
// return true if the ns has the shared label in it.
|
|
||||||
func hasSharedLabel(tx *bolt.Tx, ns string) bool {
|
|
||||||
labelsBkt := getNamespaceLabelsBucket(tx, ns)
|
|
||||||
if labelsBkt == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
cur := labelsBkt.Cursor()
|
|
||||||
for k, v := cur.First(); k != nil; k, v = cur.Next() {
|
|
||||||
if string(k) == labels.LabelSharedNamespace && string(v) == "true" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func getShareableBucket(tx *bolt.Tx, dgst digest.Digest) *bolt.Bucket {
|
|
||||||
var bkt *bolt.Bucket
|
|
||||||
nsbkt := getNamespacesBucket(tx)
|
|
||||||
cur := nsbkt.Cursor()
|
|
||||||
for k, _ := cur.First(); k != nil; k, _ = cur.Next() {
|
|
||||||
// If this bucket has shared label
|
|
||||||
// get the bucket and return it.
|
|
||||||
if hasSharedLabel(tx, string(k)) {
|
|
||||||
bkt = getBlobBucket(tx, string(k), dgst)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bkt
|
|
||||||
}
|
|
||||||
|
|
||||||
func namespaceLabelsBucketPath(namespace string) [][]byte {
|
func namespaceLabelsBucketPath(namespace string) [][]byte {
|
||||||
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectLabels}
|
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectLabels}
|
||||||
}
|
}
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/labels"
|
|
||||||
digest "github.com/opencontainers/go-digest"
|
|
||||||
bolt "go.etcd.io/bbolt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHasSharedLabel(t *testing.T) {
|
|
||||||
tmpdir, err := os.MkdirTemp("", "bucket-testing-")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := bolt.Open(filepath.Join(tmpdir, "metadata.db"), 0660, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = createNamespaceLabelsBucket(db, "testing-with-shareable", true)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = createNamespaceLabelsBucket(db, "testing-without-shareable", false)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = db.View(func(tx *bolt.Tx) error {
|
|
||||||
if !hasSharedLabel(tx, "testing-with-shareable") {
|
|
||||||
return errors.New("hasSharedLabel should return true when label is set")
|
|
||||||
}
|
|
||||||
if hasSharedLabel(tx, "testing-without-shareable") {
|
|
||||||
return errors.New("hasSharedLabel should return false when label is not set")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetShareableBucket(t *testing.T) {
|
|
||||||
tmpdir, err := os.MkdirTemp("", "bucket-testing-")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := bolt.Open(filepath.Join(tmpdir, "metadata.db"), 0660, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
goodDigest := digest.FromString("gooddigest")
|
|
||||||
imagePresentNS := "has-image-is-shareable"
|
|
||||||
imageAbsentNS := "image-absent"
|
|
||||||
|
|
||||||
// Create two namespaces, empty for now
|
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
|
||||||
_, err := createImagesBucket(tx, imagePresentNS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = createImagesBucket(tx, imageAbsentNS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that getShareableBucket is correctly returning nothing when a
|
|
||||||
// a bucket with that digest is not present in any namespace.
|
|
||||||
err = db.View(func(tx *bolt.Tx) error {
|
|
||||||
if bkt := getShareableBucket(tx, goodDigest); bkt != nil {
|
|
||||||
return errors.New("getShareableBucket should return nil if digest is not present")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a blob bucket in one of the namespaces with a well-known digest
|
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
|
||||||
_, err = createBlobBucket(tx, imagePresentNS, goodDigest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that it is still not retrievable if the shareable label is not present
|
|
||||||
err = db.View(func(tx *bolt.Tx) error {
|
|
||||||
if bkt := getShareableBucket(tx, goodDigest); bkt != nil {
|
|
||||||
return errors.New("getShareableBucket should return nil if digest is present but doesn't have shareable label")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the namespace labels bucket and mark it as shareable
|
|
||||||
err = createNamespaceLabelsBucket(db, imagePresentNS, true)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that this digest is retrievable from getShareableBucket
|
|
||||||
err = db.View(func(tx *bolt.Tx) error {
|
|
||||||
if bkt := getShareableBucket(tx, goodDigest); bkt == nil {
|
|
||||||
return errors.New("getShareableBucket should not return nil if digest is present")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNamespaceLabelsBucket(db transactor, ns string, shareable bool) error {
|
|
||||||
err := db.Update(func(tx *bolt.Tx) error {
|
|
||||||
err := withNamespacesLabelsBucket(tx, ns, func(bkt *bolt.Bucket) error {
|
|
||||||
if shareable {
|
|
||||||
err := bkt.Put([]byte(labels.LabelSharedNamespace), []byte("true"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
@ -76,10 +76,6 @@ func (cs *contentStore) Info(ctx context.Context, dgst digest.Digest) (content.I
|
|||||||
var info content.Info
|
var info content.Info
|
||||||
if err := view(ctx, cs.db, func(tx *bolt.Tx) error {
|
if err := view(ctx, cs.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getBlobBucket(tx, ns, dgst)
|
bkt := getBlobBucket(tx, ns, dgst)
|
||||||
if bkt == nil {
|
|
||||||
// try to find shareable bkt before erroring
|
|
||||||
bkt = getShareableBucket(tx, dgst)
|
|
||||||
}
|
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
|
return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
|
||||||
}
|
}
|
||||||
@ -107,13 +103,10 @@ func (cs *contentStore) Update(ctx context.Context, info content.Info, fieldpath
|
|||||||
}
|
}
|
||||||
if err := update(ctx, cs.db, func(tx *bolt.Tx) error {
|
if err := update(ctx, cs.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getBlobBucket(tx, ns, info.Digest)
|
bkt := getBlobBucket(tx, ns, info.Digest)
|
||||||
if bkt == nil {
|
|
||||||
// try to find a shareable bkt before erroring
|
|
||||||
bkt = getShareableBucket(tx, info.Digest)
|
|
||||||
}
|
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return fmt.Errorf("content digest %v: %w", info.Digest, errdefs.ErrNotFound)
|
return fmt.Errorf("content digest %v: %w", info.Digest, errdefs.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := readInfo(&updated, bkt); err != nil {
|
if err := readInfo(&updated, bkt); err != nil {
|
||||||
return fmt.Errorf("info %q: %w", info.Digest, err)
|
return fmt.Errorf("info %q: %w", info.Digest, err)
|
||||||
}
|
}
|
||||||
@ -706,10 +699,6 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err
|
|||||||
|
|
||||||
return view(ctx, cs.db, func(tx *bolt.Tx) error {
|
return view(ctx, cs.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getBlobBucket(tx, ns, dgst)
|
bkt := getBlobBucket(tx, ns, dgst)
|
||||||
if bkt == nil {
|
|
||||||
// try to find shareable bkt before erroring
|
|
||||||
bkt = getShareableBucket(tx, dgst)
|
|
||||||
}
|
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
|
return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
@ -55,28 +55,6 @@ func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error)
|
|||||||
|
|
||||||
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getImagesBucket(tx, namespace)
|
bkt := getImagesBucket(tx, namespace)
|
||||||
if bkt == nil || bkt.Bucket([]byte(name)) == nil {
|
|
||||||
nsbkt := getNamespacesBucket(tx)
|
|
||||||
cur := nsbkt.Cursor()
|
|
||||||
for k, _ := cur.First(); k != nil; k, _ = cur.Next() {
|
|
||||||
// If this namespace has the sharedlabel
|
|
||||||
if hasSharedLabel(tx, string(k)) {
|
|
||||||
// and has the image we are looking for
|
|
||||||
bkt = getImagesBucket(tx, string(k))
|
|
||||||
if bkt == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ibkt := bkt.Bucket([]byte(name))
|
|
||||||
if ibkt == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// we are done
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return fmt.Errorf("image %q: %w", name, errdefs.ErrNotFound)
|
return fmt.Errorf("image %q: %w", name, errdefs.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user