Support lease filters
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
00a99c0472
commit
29b72d4ff0
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"github.com/containerd/containerd/filters"
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
|
"github.com/containerd/containerd/leases"
|
||||||
)
|
)
|
||||||
|
|
||||||
func adaptImage(o interface{}) filters.Adaptor {
|
func adaptImage(o interface{}) filters.Adaptor {
|
||||||
@ -119,6 +120,23 @@ func adaptContentStatus(status content.Status) filters.Adaptor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func adaptLease(lease leases.Lease) filters.Adaptor {
|
||||||
|
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
|
||||||
|
if len(fieldpath) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fieldpath[0] {
|
||||||
|
case "id":
|
||||||
|
return lease.ID, len(lease.ID) > 0
|
||||||
|
case "labels":
|
||||||
|
return checkMap(fieldpath[1:], lease.Labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
|
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
return "", false
|
return "", false
|
||||||
|
@ -109,14 +109,16 @@ func TestContentLeased(t *testing.T) {
|
|||||||
|
|
||||||
func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) {
|
func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) {
|
||||||
if err := db.Update(func(tx *bolt.Tx) error {
|
if err := db.Update(func(tx *bolt.Tx) error {
|
||||||
_, err := NewLeaseManager(tx).Create(ctx, name, nil)
|
_, err := NewLeaseManager(tx).Create(ctx, leases.WithID(name))
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return leases.WithLease(ctx, name), func() error {
|
return leases.WithLease(ctx, name), func() error {
|
||||||
return db.Update(func(tx *bolt.Tx) error {
|
return db.Update(func(tx *bolt.Tx) error {
|
||||||
return NewLeaseManager(tx).Delete(ctx, name)
|
return NewLeaseManager(tx).Delete(ctx, leases.Lease{
|
||||||
|
ID: name,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -126,7 +128,7 @@ func checkContentLeased(ctx context.Context, db *DB, dgst digest.Digest) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("no namespace in context")
|
return errors.New("no namespace in context")
|
||||||
}
|
}
|
||||||
lease, ok := leases.Lease(ctx)
|
lease, ok := leases.FromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("no lease in context")
|
return errors.New("no lease in context")
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/leases"
|
"github.com/containerd/containerd/leases"
|
||||||
"github.com/containerd/containerd/metadata/boltutil"
|
"github.com/containerd/containerd/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
@ -110,12 +111,17 @@ func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List lists all active leases
|
// List lists all active leases
|
||||||
func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Lease, error) {
|
func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease, error) {
|
||||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter, err := filters.ParseAll(fs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
var ll []leases.Lease
|
var ll []leases.Lease
|
||||||
|
|
||||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||||
@ -146,7 +152,9 @@ func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Le
|
|||||||
}
|
}
|
||||||
l.Labels = labels
|
l.Labels = labels
|
||||||
|
|
||||||
|
if filter.Match(adaptLease(l)) {
|
||||||
ll = append(ll, l)
|
ll = append(ll, l)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -107,3 +107,153 @@ func TestLeases(t *testing.T) {
|
|||||||
t.Fatalf("Expected no leases, found %d: %v", len(listed), listed)
|
t.Fatalf("Expected no leases, found %d: %v", len(listed), listed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLeasesList(t *testing.T) {
|
||||||
|
ctx, db, cancel := testEnv(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
testset := [][]leases.Opt{
|
||||||
|
{
|
||||||
|
leases.WithID("lease1"),
|
||||||
|
leases.WithLabels(map[string]string{
|
||||||
|
"label1": "value1",
|
||||||
|
"label3": "other",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leases.WithID("lease2"),
|
||||||
|
leases.WithLabels(map[string]string{
|
||||||
|
"label1": "value1",
|
||||||
|
"label2": "",
|
||||||
|
"label3": "other",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leases.WithID("lease3"),
|
||||||
|
leases.WithLabels(map[string]string{
|
||||||
|
"label1": "value2",
|
||||||
|
"label2": "something",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert all
|
||||||
|
for _, opts := range testset {
|
||||||
|
if err := db.Update(func(tx *bolt.Tx) error {
|
||||||
|
lm := NewLeaseManager(tx)
|
||||||
|
_, err := lm.Create(ctx, opts...)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range []struct {
|
||||||
|
name string
|
||||||
|
filters []string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "All",
|
||||||
|
filters: []string{},
|
||||||
|
expected: []string{"lease1", "lease2", "lease3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ID",
|
||||||
|
filters: []string{"id==lease1"},
|
||||||
|
expected: []string{"lease1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IDx2",
|
||||||
|
filters: []string{"id==lease1", "id==lease2"},
|
||||||
|
expected: []string{"lease1", "lease2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Label1",
|
||||||
|
filters: []string{"labels.label1"},
|
||||||
|
expected: []string{"lease1", "lease2", "lease3"},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "Label1value1",
|
||||||
|
filters: []string{"labels.label1==value1"},
|
||||||
|
expected: []string{"lease1", "lease2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Label1value2",
|
||||||
|
filters: []string{"labels.label1==value2"},
|
||||||
|
expected: []string{"lease3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Label2",
|
||||||
|
filters: []string{"labels.label2"},
|
||||||
|
expected: []string{"lease3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Label3",
|
||||||
|
filters: []string{"labels.label2", "labels.label3"},
|
||||||
|
expected: []string{"lease1", "lease2", "lease3"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
if err := db.View(func(tx *bolt.Tx) error {
|
||||||
|
lm := NewLeaseManager(tx)
|
||||||
|
results, err := lm.List(ctx, testcase.filters...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(results) != len(testcase.expected) {
|
||||||
|
t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMap := map[string]struct{}{}
|
||||||
|
for _, expected := range testcase.expected {
|
||||||
|
expectedMap[expected] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, result := range results {
|
||||||
|
if _, ok := expectedMap[result.ID]; !ok {
|
||||||
|
t.Errorf("unexpected match: %v", result.ID)
|
||||||
|
} else {
|
||||||
|
delete(expectedMap, result.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(expectedMap) > 0 {
|
||||||
|
for match := range expectedMap {
|
||||||
|
t.Errorf("missing match: %v", match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete everything to test it
|
||||||
|
for _, opts := range testset {
|
||||||
|
var lease leases.Lease
|
||||||
|
for _, opt := range opts {
|
||||||
|
if err := opt(&lease); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Update(func(tx *bolt.Tx) error {
|
||||||
|
lm := NewLeaseManager(tx)
|
||||||
|
return lm.Delete(ctx, lease)
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try it again, get nil
|
||||||
|
if err := db.Update(func(tx *bolt.Tx) error {
|
||||||
|
lm := NewLeaseManager(tx)
|
||||||
|
return lm.Delete(ctx, lease)
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("unexpected error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user